From 7b2894398704367c045b012f9b396ac999a40f49 Mon Sep 17 00:00:00 2001 From: ralongit Date: Thu, 12 Oct 2023 15:15:23 +0300 Subject: [PATCH 1/2] Add serverless docs - Log4net serverless section - NLog serverless section - LoggerFactory serverless section - SeriLog serverless section --- docs/shipping/Code/dotnet.md | 184 ++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 2 deletions(-) diff --git a/docs/shipping/Code/dotnet.md b/docs/shipping/Code/dotnet.md index 9be1c7bc..1d2871d8 100644 --- a/docs/shipping/Code/dotnet.md +++ b/docs/shipping/Code/dotnet.md @@ -301,6 +301,53 @@ namespace dotnet_log4net } ``` +##### Serverless platforms +If you’re using a serverless function, you’ll need to call the appender's flush methods at the end of the function run to make sure the logs are sent before the function finishes its execution. + +###### Code sample + +```csharp +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using log4net; +using MicrosoftLogger = Microsoft.Extensions.Logging.ILogger; +using MicrosoftLoggerFactory = Microsoft.Extensions.Logging.LoggerFactory; +using System.IO; +using System.Reflection; +using log4net.Config; +using System; +using System.Threading; +namespace LogzioLoggerFactorySampleApplication +{ + public class TimerTriggerCSharpLoggerFactory + { + [FunctionName("TimerTriggerCSharpLoggerFactory")] + public void Run([TimerTrigger("*/30 * * * * *")] TimerInfo myTimer, MicrosoftLogger msLog, Microsoft.Azure.WebJobs.ExecutionContext context) + { + + msLog.LogInformation($"LoggerFactory C# Timer trigger function executed at: {DateTime.Now}"); + + var functionAppDirectory = context.FunctionAppDirectory; // Function app root directory + MicrosoftLoggerFactory loggerFactory = new(); + loggerFactory.AddLog4Net(Path.Combine(functionAppDirectory, "log4net.config")); // Use the log4net.config in the function app root directory + var logger = loggerFactory.CreateLogger(); + + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + + // Replace "App.config" with the config file that holds your log4net configuration + XmlConfigurator.Configure(logRepository, new FileInfo(Path.Combine(functionAppDirectory, "log4net.config"))); + + logger.LogInformation("Hello"); + logger.LogInformation("Is it me you looking for?"); + LogManager.Flush(5000); + LogManager.Shutdown(); + msLog.LogInformation($"LoggerFactory C# Timer trigger function finishd at: {DateTime.Now}"); + + } + } +} +``` + ### NLog @@ -344,7 +391,7 @@ For a complete list of options, see the configuration parameters below the code token="<>" logzioType="nlog" listenerUrl="<>:8071" - bufferSize="100" bufferTimeout="00:00:05" @@ -435,7 +482,7 @@ namespace LogzioNLogSampleApplication .Property("youCanCallMe", "Al") .Write(); - LogManager.Shutdown(); + LogManager.Shutdown(); } } } @@ -516,7 +563,53 @@ config.AddRule(LogLevel.Debug, LogLevel.Fatal, logzioTarget); LogManager.Configuration = config; ``` +##### Serverless platforms +If you’re using a serverless function, you’ll need to call the appender's flush methods at the end of the function run to make sure the logs are sent before the function finishes its execution. +###### Code sample + +```csharp +using System; +using Microsoft.Azure.WebJobs; +using Logzio.DotNet.NLog; +using NLog; +using NLog.Config; +using NLog.Fluent; +using Microsoft.Extensions.Logging; +using MicrosoftLogger = Microsoft.Extensions.Logging.ILogger; +namespace LogzioNLogSampleApplication +{ + public class TimerTriggerCSharpNLog + { + [FunctionName("TimerTriggerCSharpNLog")] + public void Run([TimerTrigger("*/30 * * * * *")] TimerInfo myTimer, MicrosoftLogger msLog) + { + msLog.LogInformation($"NLogzio C# Timer trigger function executed at: {DateTime.Now}"); + + var nLog = LogManager.GetCurrentClassLogger(); + + nLog.Info() + .Message("If you'll be my bodyguard") + .Property("iCanBe", "your long lost pal") + .Property("iCanCallYou", "Betty, and Betty when you call me") + .Property("youCanCallMe", "Al") + .Write(); + + // Call Flush with a callback to Shutdown LogManager + LogManager.Flush(ex => + { + if (ex != null) + msLog.LogError(ex, "Error while flushing NLog."); + else + { + LogManager.Shutdown(); + msLog.LogInformation($"NLogzio C# Timer trigger function finished at: {DateTime.Now}"); + } + }, TimeSpan.FromSeconds(5)); + } + } +} +``` ### LoggerFactory @@ -781,7 +874,52 @@ hierarchy.Root.Level = Level.All; hierarchy.Configured = true; ``` +##### Serverless platforms +If you’re using a serverless function, you’ll need to call the logger's shutdown methods at the end of the function run and make sure the logs are sent before the function finishes its execution. Make sure 'debug' is set to false if the function is deployed as it might cause permission issues with debug files. + +###### Code sample +```csharp +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using log4net; +using MicrosoftLogger = Microsoft.Extensions.Logging.ILogger; +using MicrosoftLoggerFactory = Microsoft.Extensions.Logging.LoggerFactory; +using System.IO; +using System.Reflection; +using log4net.Config; +using System; +using System.Threading; +namespace LogzioLoggerFactorySampleApplication +{ + public class TimerTriggerCSharpLoggerFactory + { + [FunctionName("TimerTriggerCSharpLoggerFactory")] + public void Run([TimerTrigger("*/30 * * * * *")] TimerInfo myTimer, MicrosoftLogger msLog, Microsoft.Azure.WebJobs.ExecutionContext context) + { + + msLog.LogInformation($"LoggerFactory C# Timer trigger function executed at: {DateTime.Now}"); + + var functionAppDirectory = context.FunctionAppDirectory; // Function app root directory + MicrosoftLoggerFactory loggerFactory = new(); + loggerFactory.AddLog4Net(Path.Combine(functionAppDirectory, "log4net.config")); // Use the log4net.config in the function app root directory + var logger = loggerFactory.CreateLogger(); + + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + + // Replace "App.config" with the config file that holds your log4net configuration + XmlConfigurator.Configure(logRepository, new FileInfo(Path.Combine(functionAppDirectory, "log4net.config"))); + + logger.LogInformation("Hello"); + logger.LogInformation("Is it me you looking for?"); + Thread.Sleep(5000); // gives the logs enough time to be sent to Logz.io + LogManager.Shutdown(); + msLog.LogInformation($"LoggerFactory C# Timer trigger function finishd at: {DateTime.Now}"); + + } + } +} +``` ### Serilog :::note @@ -904,6 +1042,48 @@ namespace Example } ``` +##### Serverless platforms +If you’re using a serverless function, you’ll need to call the appender's flush methods at the end of the function run to make sure the logs are sent before the function finishes its execution. +In the Serilog integration, you should use the 'WriteTo.LogzIo()' instad of 'WriteTo.LogzIoDurableHttp()' method as it uses in-memory buffering which is best practice for serverless functions. +###### Code sample + +```csharp +using System; +using Microsoft.Azure.WebJobs; +using Serilog; +using Serilog.Sinks.Logz.Io; +using Microsoft.Extensions.Logging; +using MicrosoftLogger = Microsoft.Extensions.Logging.ILogger; +using Serilogger = Serilog.ILogger; +using System.Threading; + + +namespace LogzioSeriLogSampleApplication +{ + public class TimerTriggerCSharpSeriLogzio + { + [FunctionName("TimerTriggerCSharpSeriLogzio")] + public void Run([TimerTrigger("*/30 * * * * *")] TimerInfo myTimer, MicrosoftLogger msLog) + { + msLog.LogInformation($"Serilog C# Timer trigger function executed at: {DateTime.Now}"); + Serilogger logzioLogger = new LoggerConfiguration() + .WriteTo.LogzIo("<>", "<>", useHttps: true, dataCenterSubDomain: "listener") // Replace 'listener' with the relevant region, i.e: 'listener-eu' + .CreateLogger(); + + // Assign the logger to the static Log class + Log.Logger = logzioLogger; + + logzioLogger.Information("Hello. Is it me you're looking for?"); + Thread.Sleep(5000); + // // Flush the static logger + Log.CloseAndFlush(); + + msLog.LogInformation($"Serilog C# Timer trigger function finished at: {DateTime.Now}"); + } + } +} +``` + {@include: ../../_include/log-shipping/log-shipping-token.html} {@include: ../../_include/log-shipping/listener-var.html} From a83b588b8851f2d06881a90383a2d14803a6b037 Mon Sep 17 00:00:00 2001 From: ralongit Date: Thu, 12 Oct 2023 15:22:20 +0300 Subject: [PATCH 2/2] Fix log4net example --- docs/shipping/Code/dotnet.md | 47 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/docs/shipping/Code/dotnet.md b/docs/shipping/Code/dotnet.md index 1d2871d8..2689794e 100644 --- a/docs/shipping/Code/dotnet.md +++ b/docs/shipping/Code/dotnet.md @@ -307,41 +307,40 @@ If you’re using a serverless function, you’ll need to call the appender's fl ###### Code sample ```csharp +using System; using Microsoft.Azure.WebJobs; using Microsoft.Extensions.Logging; using log4net; +using log4net.Core; +using log4net.Repository.Hierarchy; +using Logzio.DotNet.Log4net; using MicrosoftLogger = Microsoft.Extensions.Logging.ILogger; -using MicrosoftLoggerFactory = Microsoft.Extensions.Logging.LoggerFactory; -using System.IO; -using System.Reflection; -using log4net.Config; -using System; -using System.Threading; -namespace LogzioLoggerFactorySampleApplication + +namespace LogzioLog4NetSampleApplication { - public class TimerTriggerCSharpLoggerFactory + public class TimerTriggerCSharpLog4Net { - [FunctionName("TimerTriggerCSharpLoggerFactory")] - public void Run([TimerTrigger("*/30 * * * * *")] TimerInfo myTimer, MicrosoftLogger msLog, Microsoft.Azure.WebJobs.ExecutionContext context) + [FunctionName("TimerTriggerCSharpLog4Net")] + public void Run([TimerTrigger("*/30 * * * * *")]TimerInfo myTimer, MicrosoftLogger msLog) { + msLog.LogInformation($"Log4Net C# Timer trigger function executed at: {DateTime.Now}"); + var hierarchy = (Hierarchy)LogManager.GetRepository(); + var logger = LogManager.GetCurrentClassLogger(); + var logzioAppender = new LogzioAppender(); - msLog.LogInformation($"LoggerFactory C# Timer trigger function executed at: {DateTime.Now}"); - - var functionAppDirectory = context.FunctionAppDirectory; // Function app root directory - MicrosoftLoggerFactory loggerFactory = new(); - loggerFactory.AddLog4Net(Path.Combine(functionAppDirectory, "log4net.config")); // Use the log4net.config in the function app root directory - var logger = loggerFactory.CreateLogger(); - - var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); - - // Replace "App.config" with the config file that holds your log4net configuration - XmlConfigurator.Configure(logRepository, new FileInfo(Path.Combine(functionAppDirectory, "log4net.config"))); + logzioAppender.AddToken("<>"); + logzioAppender.AddListenerUrl("https://<>:8071"); + logzioAppender.ActivateOptions(); - logger.LogInformation("Hello"); - logger.LogInformation("Is it me you looking for?"); + hierarchy.Root.AddAppender(logzioAppender); + hierarchy.Configured = true; + hierarchy.Root.Level = Level.All; + logger.Info("Now I don't blame him 'cause he run and hid"); + logger.Info("But the meanest thing he ever did"); + logger.Info("Before he left was he went and named me Sue"); LogManager.Flush(5000); LogManager.Shutdown(); - msLog.LogInformation($"LoggerFactory C# Timer trigger function finishd at: {DateTime.Now}"); + msLog.LogInformation($"Log4Net C# Timer trigger function finishd at: {DateTime.Now}"); } }