Azure Function - Unable to log message to Application insights from service class - azure

I am facing issues in logging messages from the service class of Azure Function app. There are no issues in logging from the function class. I followed the solution mentioned on Azure Functions - ILogger Logging across classes but cant figure out the issue.
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
},
"logLevel": {
"FunctionApp.Services.RestService": "Information"
}
}
}
RestService.cs
public class RestService : IRestService
{
private readonly ILogger<IRestService> _logger;
public RestService(ILogger<IRestService> logger)
{
_logger = logger;
}
public async Task<RestResponse> SampleMethod()
{
_logger.LogInformation("************************************TEST THIS WORK************************************","1212121212");
}
}
IRestService.cs
public interface IRestService
{
Task<RestResponse> SampleMethod(string url, string requestBody, string soapAction);
}
I am calling the RestService class from the function app.
Startup.cs
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IRestService, RestService>();
}
}
As mentioned earlier, the log messages from the function class appears in App Insight but not from the service class. What am I missing?

I have reproduced in my environment and got expected results as below:
You need to change Host.json file.
host.json:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
},
"logLevel": {
"Function": "Information"
}
}
}
Taken Code from (for Class, Interface class, Startup and main function) reference (Link)
I have written similar code as you but changed Host.json code. Try to change hots.json and you will get output as I have got.

Related

Azure Function App Dependency Inject Logger not logging

I have a Function App that I’m trying to using DI in a class for the logger so that I don’t have to pass the ILogger to every function. I’ve been doing some researching and found where I’m supposed to use ILogger in the class constructor. I’ve done all of the changes I believe are correct but it’s still not logging anything from that class.
I’ve added the logging to my Startup class, updated the hosts.json file, and used ILogger in the constructor. There are no errors but nothing gets logged. Does anyone see something I’m missing?
Startup.cs
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging();
builder.Services.AddTransient<IDataManager, DataManager>();
}
Host.json
{
"version": "2.0",
"logging": {
"fileLoggingMode": "always",
"logLevel": {
"default": "Debug"
},
"applicationInsights": {
"samplingSettings": {
"isEnabled": false,
"excludedTypes": "Request"
}
}
}
}
DataManager.cs
public class DataManager : IDataManager
{
private DataContext _db;
private readonly ILogger<DataManager> _log;
public DataManager(ILogger<DataManager> log, DataContext dataContext)
{
_db = dataContext;
_log = log;
}
}
I have reproduced in my environment and got expected results as below and the code taken from #nareshnagpal06 's GitHub repository:
Startup.cs:
using Microsoft.Azure.Functions.Extensions.DependencyInjection; // install nuget - "Microsoft.Azure.Functions.Extensions"
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
[assembly: FunctionsStartup(typeof(FunctionApp50.Startup))]
namespace FunctionApp50
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IHelperClass, HelperClass>();
}
}
}
HelperClass.cs:
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
namespace FunctionApp50
{
public class HelperClass : IHelperClass
{
private static ILogger<IHelperClass> _logger;
public HelperClass(ILogger<IHelperClass> logger)
{
_logger = logger;
}
public void Dowork()
{
_logger.LogInformation("Dowork: Execution Started");
/* rest of the functionality below
.....
.....
*/
_logger.LogInformation("Dowork: Execution Completed");
}
}
}
IHelperClass.cs:
using System;
using System.Collections.Generic;
using System.Text;
namespace FunctionApp50
{
public interface IHelperClass
{
void Dowork();
}
}
Function1.cs:
using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
namespace FunctionApp50
{
public class Function1 // Ensure class is not static (which comes by default)
{
private IHelperClass _helper;
public Function1(IHelperClass helper)
{
_helper = helper;
}
[FunctionName("Function1")]
public void Run([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
// call helper
_helper.Dowork();
}
}
}
host.json:
{
"version": "2.0",
"logging": {
"fileLoggingMode": "always",
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
},
"logLevel": {
"Function": "Information"
}
}
}
Terminal Output:
File Output:
Firstly go to run, then paste %temp%\LogFiles\Application\Functions.,then click on Host file in the location then click on log file then the output is:

How do I log results from an Azure Function App dependency?

I have an Azure Function App project with the following files:
Startup.cs: Registers a dependency
[assembly: FunctionsStartup(typeof(MyLoggingFunction.Startup))]
namespace MyLoggingFunction
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<MyService>();
}
}
}
MyService.cs: Writes a log message
namespace MyLoggingFunction
{
public class MyService
{
private readonly ILogger<MyService> logger;
public MyService(ILogger<MyService> logger)
{
this.logger = logger;
}
public void Go()
{
this.logger.LogInformation("MyService.Go");
}
}
}
MyFunction.cs: The actual function; uses MyService
namespace MyLoggingFunction
{
public class MyFunction
{
private readonly MyService myService;
public MyFunction(MyService myService)
{
this.myService = myService;
}
[FunctionName("MyFunction")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
this.myService.Go();
log.LogInformation("All done");
return new OkObjectResult("Done.");
}
}
}
Here is the output visible in Azure after the function runs successfully. Note that the log message from the injected dependency is missing:
How do I get log messages from the dependency to show up as part of the built-in logging?
Add logging level entry to host.json :
{
"version": "2.0",
"logging": {
"logLevel": {
"default": "Information"
}
}
}
You must whitelist the classes and/or namespaces from which you want to allow logging. An example hosts.json file:
{
"logging": {
"logLevel": {
"MyLoggingFunction": "Information"
}
},
"version": "2.0"
}
This is documented as an issue on the azure-function-host GitHub repository.

Azure Functions and Dependency Injection

I have the following Startup class in my Azure Function v2 project:
[assembly: FunctionsStartup(typeof(AzureAppDomainRegistration.Startup))]
namespace AzureAppDomainRegistration
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var connString = System.Configuration.ConfigurationManager.AppSettings["ConnectionStrings:DataContext"];
//var connString = config["ConnectionStrings:DataContext"];
builder.Services.AddDbContext<DataContext>(options => options
.UseLazyLoadingProxies()
.UseSqlServer(connString));
builder.Services.AddTransient<IActionsRegistrationInfo, EfActionsRegistrationInfo>();
}
}
}
and Function:
public class Function100_CheckEmail
{
readonly IActionsRegistrationInfo _actionsRegistrationInfo;
public Function100_CheckEmail(IActionsRegistrationInfo actionsRegistrationInfo)
{
_actionsRegistrationInfo = actionsRegistrationInfo;
}
[FunctionName("Function100_CheckEmail")]
//public static IActionResult Run(
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
[Queue("email-message-admin-confirmation", Connection = "StorageConnectionString")]CloudQueue outputQueue,
ExecutionContext context,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
but when this function is being executed, I get the following errors on Azure Portal:
without DI it works fine. What is wrong?
.NET Core 2.2
ADDED:
I tried to remote debugger and I see, that Configure method of Startup file has exceptions (logged by App Insights) with ArgumentNullException, but no details. What can be it?
So in order to get a Environment Variable in Azure functions, you need to use
var connStr = Environment.GetEnvironmentVariable("ConnectionStrings:SQLConnectionString", EnvironmentVariableTarget.Process);
Also check if you have the value in local.settings.json which looks something like this
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "<connection string>",
"AzureWebJobsDashboard": "<connection string>"
},
"Host": {
"LocalHttpPort": 7071,
"CORS": "*"
},
"ConnectionStrings": {
"SQLConnectionString": "Value"
}
}
Refereces :
MSFT Docs
A good article

IPFiltering Asp Net Core

I'm using the following nuget package : https://github.com/msmolka/ZNetCS.AspNetCore.IPFiltering
I'm using it to block IP that are trying to bruteforce the authentication of my app.
The Blacklist is defined in the appsetting.json, and I don't know how to dynamicaly modify it during runtime, for example, add an IP that has a bad password.
The way I'm actually doing isn't working as I still can connect even if the IP is correctly persisted in the conf ...
Startup.cs
namespace Sondage
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIPFiltering(this.Configuration.GetSection("IPFiltering"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseIPFiltering();
app.UseHttpsRedirection();
app.UseMvc();
}
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"IPFiltering": {
"DefaultBlockLevel": "None",
"HttpStatusCode": 404,
"Blacklist": [],
"IgnoredPaths": [ "GET:/ignoreget", "*:/ignore" ]
}
}
Part of my controller :
[Route("api/authenticate")]
[ApiController]
public class authenticationController : ControllerBase
{
private IConfiguration _configuration;
public authenticationController(IConfiguration Configuration)
{
_configuration = Configuration;
}
[HttpPost]
public string authent(string value)
{
Dictionary<string, string> result = new Dictionary<string, string>();
IPAddress ip_addr = HttpContext.Connection.RemoteIpAddress;
if(!Globals.tryByIP.TryGetValue(ip_addr, out int numberOfTry)) {
Globals.tryByIP.Add(ip_addr, 0);
} else
{
if(numberOfTry>=0)
{
Console.WriteLine("-----");
_configuration.GetSection("IPFiltering")["Blacklist"] = ip_addr.ToString();
Console.WriteLine(_configuration.GetSection("IPFiltering")["Blacklist"]);
}
}
Make sure to use the IPAddressRange package as well.
I had problems recently with this nuget package as well, and at first I forgot to add the ipaddress parser.

Configure Column Options for Serilog Sinks MsSqlServer in AppSettings.json

I'm trying to determine if it's possible to configure the column options for serilog sink mssqlserver in the appsettings.json file for an ASP.Net Core 2 project.
I create and configure the logger in the Program.cs file.
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
.Build();
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
//.Enrich.WithProperty("AppName", "One Badass App") // Adds property to XML structure in properties column
.ReadFrom.Configuration(Configuration)
.CreateLogger();
try
{
Log.Information("Starting web host");
BuildWebHost(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
I can build the configuration file from the appsettings.json file, which contains a Serilog node with information for which connection string and table to use.
{
"AppSettings": {
"Application": {
"Name": "Payment Processing API",
"Version": "1.0"
}
},
"ConnectionStrings": {
"localPaymentProcessingDb": "Server=(localdb)\\mssqllocaldb;Database=PaymentProcessing;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Serilog": {
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=(localdb)\\mssqllocaldb;Database=PaymentProcessing;Trusted_Connection=True;MultipleActiveResultSets=true",
"tableName": "Logs"
}
}
]
}
There's an open issue on Github for this, but I haven't found any other information about it.
If column options can't be configured in the appsettings.json, where and how should they be configured in an ASP.Net Core 2 project?
If anyone else stumbles across this same issue the linked GitHub issue in the question now contains the answer:
This is now possible with the latest SQL sink and
Serilog.Settings.Configuration packages.
Also, I know this question asks for a .NET Core 2 answer, and it sounds like the linked GitHub page answers this for 2, I am using .NET Core 3.1 and the following worked for me (hopefully it works for 2 as well)
I installed the Serilog.Settings.Configuration Nuget package and used the following Serilog appsettings.json configuration:
"Serilog":{
"MinimumLevel":"Information",
"WriteTo":[
{
"Name":"MSSqlServer",
"Args":{
"connectionString":"DbContext",
"tableName":"EventLog",
"autoCreateSqlTable":true,
"columnOptionsSection":{
"addStandardColumns":[
"LogEvent"
],
"removeStandardColumns":[
"MessageTemplate",
"Properties"
]
}
}
}
]
}
For accessing Serilog from appsettings in Code, you could bind Serilog node to Serilog class.
Here are the detail steps.
1. Create Serilog Configuration Class
public class SerilogConfiguration
{
public LogEventLevel MinimumLevel { get; set; }
public List<WriteTo> WriteTo { get; set; }
}
public class WriteTo
{
public string Name { get; set; }
public Args Args { get; set; }
}
public class Args
{
public string ConnectionString { get; set; }
public string TableName { get; set; }
public List<StandardColumn> Add { get; set; }
public List<StandardColumn> Remove { get; set; }
}
Configure appsettings.json
Code:
{
"Serilog": {
"MinimumLevel": "Error",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "<our connection string>",
"tableName": "Log",
"Remove": [ "Properties" ],
"Add": [ "LogEvent" ]
}
}
]
}
}
Bind appsetting.json to class
public void ConfigureServices(IServiceCollection services)
{
services.Configure<SerilogConfiguration>(Configuration.GetSection("Serilog"));
}
Access Configuration
public class HomeController : Controller {
private readonly SerilogConfiguration _configuration;
public HomeController(IOptions<SerilogConfiguration> configuration)
{
_configuration = configuration.Value;
}
public IActionResult AppSettings()
{
var columnOptions = new ColumnOptions();
var MSSqlServer = _configuration.WriteTo.Where(wt => wt.Name == "MSSqlServer").FirstOrDefault();
// Don't include the Properties XML column.
foreach(var columnRemove in MSSqlServer.Args.Remove)
{
columnOptions.Store.Remove(columnRemove);
}
// Do include the log event data as JSON.
foreach (var columnAdd in MSSqlServer.Args.Add)
{
columnOptions.Store.Add(columnAdd);
}
Log.Logger = new LoggerConfiguration()
.WriteTo.MSSqlServer(MSSqlServer.Args.ConnectionString, MSSqlServer.Args.TableName, columnOptions: columnOptions,
restrictedToMinimumLevel: _configuration.MinimumLevel)
.CreateLogger();
return Ok("OK");
} }

Resources