Context:
Having looked over numerous answers and documentation. I am having to resort to asking others and I am thankful for your help.
C# configuration: https://docs.datadoghq.com/logs/log_collection/csharp/?tab=serilog
Support EU endpoints (My DataDog is on an eu server): https://docs.datadoghq.com/logs/log_collection/?tab=host#supported-endpoints
Github documentation for Serilog: https://github.com/DataDog/serilog-sinks-datadog-logs
My set up:
I have a DataDog trial account
I have a DataDog agent installed locally but I actually want to send logs to DataDog with an agentless approach
My logger makes logs into my Log/log.json files although It doesn't seem to update the file immediatley and can take several minutes to finally place the information into the file (no idea why)
I have the following dependencies installed as per the serilog documentation:
I have a .Net 6 project for an Angular App.
I have an appsettings.json that looks like this:
{
"AllowedHosts": "*",
"ConnectionStrings": {
"SitePageToSitePageModernConnection": "Data Source=.\\SQLEXPRESS;Initial Catalog=Blah;Integrated Security=True;MultipleActiveResultSets=True;TrustServerCertificate=True"
},
"Serilog": {
"Using": [
"Serilog.Sinks.File",
"Serilog.Sinks.Console",
"Serilog.Sinks.Datadog.Logs"
],
"MinimumLevel": {
"Default": "Error",
"Override": {
"Microsoft": "Error",
"System": "Error",
"My.App.Namespace.Something": "Information"
}
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs/log.json",
"rollingInterval": "Day", // When a new file is created
"flushToDiskInterval": "00:00:01", // Currently does nothing. seems to be overwritten by operating system's paging cache interval (whatever that is)
"retainedFileCountLimit": 7 // How many files should be retained over the days specified by rollingInterval
}
},
{
"Name": "DatadogLogs",
"Args": {
"apiKey": "d7...b07",
"source": "something",
"host": "noideawhatgoeshere",
"configuration": {
"Url": "http-intake.logs.datadoghq.eu"
}
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithThreadId"
],
"Properties": {
"Application": "MyApplicationSample"
}
}
}
I am setting up the Serilog in the following manner:
// WebApplicationBuilder builder...
builder.Services.AddLogging(loggingBuilder =>
{
ConfigurationManager configurationManager = builder.Configuration;
Logger logger = new LoggerConfiguration()
.ReadFrom
.Configuration(configurationManager)
.CreateLogger();
// Adds serilog to the logging providers
loggingBuilder.AddSerilog(logger);
});
In a controller, I am using ILogger<MySiteController> to log.
// constructor injects:
...ILogger<MySiteController> _logger...
// call to controller runs some logs:
logger.LogInformation("Test information");
logger.LogError("Test error");
logger.LogWarning("Test warning");
My question/problem:
None of my logs end up in DataDog. Any ideas what I'm missing or misunderstanding?
The URL configured, in this case, was incorrect and should have been:
"configuration": {
"url": "https://http-intake.logs.datadoghq.eu",
"port": 443
}
For more information, I have laid out some comments to help others in the future:
{
// ...
//"AllowedHosts": "*",
// ...
// Serilog framework can look at this to configure itself
"Serilog": {
// This determines which of the types of logging you want to have
"Using": [
// This is for logging into a file in a static manner
"Serilog.Sinks.File",
// This is for logging into a file that can be configured to log for a day and then create a new file at the next day (a rolling file, get it?)
"Serilog.Sinks.RollingFile",
// This will allow logs to go into your console. Console in this case (for an Angular driven app, means the Terminal that appears when you launch your app)
"Serilog.Sinks.Console",
// This will allow logging to Datadog
"Serilog.Sinks.Datadog.Logs"
],
// These are the log levels you want to support
"MinimumLevel": {
// By default, you could say "I only want to see errors coming up"
"Default": "Error",
// If you are wanting to see information or debug or trace etc logs from other specific c# class namespaces, then you can configure them here
"Override": {
// Anything in a namespace that starts with `Microsoft` we only care about Errors being flagged (for example)
"Microsoft": "Error",
// Anything in a namespace that starts with `System` we only care about Errors being flagged (for example)
"System": "Error",
// If you had a tool with a C# class's namespace of "My.Tooling.Test", you, in this case will probably want to see all the logs you raise. so we could set this to Information (for example)
"My.Tooling.Test": "Information"
}
},
// Given that we have defined which frameworks we want to make use of in the "Using" section, we can now use the framework functionality for Console, File, RollingFile, Datadog, etc.
"WriteTo": [
// Tells Serilog to log stuff to the console
{
"Name": "Console"
//... You can configure more here but you'll need to Google that yourself
},
// Tells Serilog to log stuff to a File
{
"Name": "File",
//... You can configure more here but you'll need to Google that yourself
"Args": {
"path": "App_Data\\logs\\log.txt",
"rollingInterval": 3,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D%APP_DOMAIN_ID%/T{ThreadId}] {Level:u4} {CorrelationId} {UserId} - {Message:lj}{Exception}{NewLine}"
}
},
// Tells Serilog to log stuff to a Rolling File
{
"Name": "RollingFile",
//... You can configure more here but you'll need to Google that yourself.
"Args": {
"path": "App_Data\\logs\\DiagnosticTraceLog.txt{RollingDate}",
"shared": true,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D%APP_DOMAIN_ID%/T{ThreadId}] {Level:u4} {CorrelationId} {UserId} - {Message:lj}{Exception}{NewLine}"
}
},
// Tells Serilog to log stuff to a DataDog instance
{
// This name is important! It must be precisely this to work!
"Name": "DatadogLogs",
// The configuration properties here must all be written precisely as the following are
"Args": {
// Mandatory | API Key - Found in Datadog Organization/Api Keys section.
"apiKey": "6c...91",
// Optional | An arbitrary "source" that enables you to filter to your logs within the DataDog application
"source": "anything.you.want",
// Optional | An arbitrary "servive" that enables you to filter to your logs within the DataDog application
"service": "anything.you.want",
// Optional | An arbitrary "host" that enables you to filter to your logs within the DataDog application
"host": "anything.you.want",
// Optional | Arbitrary "tags" that enables you to filter to your logs within the DataDog application
"tags": [ "app.name:My.Tooling.Test" ],
// Optional | The default Datadog server is "intake.logs.datadoghq.com". If your DataDog instance is on the "app.datadoghq.com" URL, you do not need any of this configuration.
//
// | If you are not on the default Datadog server, you will need to find out what server you are on by visiting here and using the dropdown at the right https://docs.datadoghq.com/getting_started/site/
// | and then, once you know the server, you can visit here for the URL to use: https://docs.datadoghq.com/logs/log_collection/?tab=host#supported-endpoints
//
// | IMPORTANT: the URLs are not quite the entire URL that's needed. Be aware that "https://" will need to be placed on to determine which type you want to use. For example:
"configuration": {
"url": "https://http-intake.logs.datadoghq.eu",
"port": 443
}
}
}
],
// This ends up being stored in the final log message that is raised for you. You'll see it in DataDog under "properties" object where it mentions "Thread Id" or "SourceContext" for example.
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
// This ends up being stored in the final log message that is raised for you. You'll see it in DataDog under "properties" object where it mentions "Application".
"Properties": {
"Application": "My.Tooling.Test"
}
}
}
And specifically for c# apps, the following packages are required to be installed to use the above appsettings.json:
Mandatory stuff:
microsoft.extensions.configuration.json
serilog.aspnetcore
Sink types (The usings defined in appsettings.json):
serilog.sinks.datadog.logs
serilog.sinks.file
serilog.sinks.rollingfile
Enrichers that you've used:
serilog.enrichers.environment
serilog.enrichers.thread
serilog.settings.configuration
serilog.aspnetcore.enrichers.correlationid
Which can all be configured in C# like so (You have 2 choices):
// This allows you to add a Logging Provider to the already filled out list of logging providers
// that are supplied by default to your application.
builder.Services.AddLogging(loggingBuilder =>
{
// Get the builder's configuration from your Program
// (It essentially just gets the appsettings.json file)
ConfigurationManager configurationManager = builder.Configuration;
// Create a new LoggerConfiguration so that you can tell
// it to get its configuration from your appsettings.json file
Logger logger = new LoggerConfiguration()
.ReadFrom
.Configuration(configurationManager)
// Finally create the logger which will be used
.CreateLogger();
// Adds serilog to the logging providers
loggingBuilder.AddSerilog(logger);
});
OR
// Forces all logs to go through your single serilog configuration
// Be aware that if you use this, you need to ensure you configure your Serilog to
// do Console logging, otherwise you won't see any logs in the console.
// Luckily, I've provided all the code you need to do that in the appsettings.json configuration
// (But you may need to change the log level to Information or Debug for it to show up)
builder.Host.UseSerilog((hostingContext, services, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration);
});
And you can finally create logs by injecting the ILogger<YOURCLASSNAME> logger into the class where you want to use it and running the following commands:
logger.LogInformation("{message}", "Test");
logger.LogWarning("{message}", "Test");
logger.LogError("{message} {exception}", "Test", error);
logger.LogWarning(JsonConvert.SerializeObject(new Something() { Name = "Something", Description = "Something" }));
I am trying to upgrade the .netcore framework from 2.2 to 3.1 .
But I want to use IHostingEnvironment, IWebHostBuilder and AddNewtonsoftJson in 3.1 also.
(I know they should be replaced but if I will do so, code refactoring will be required, which i don't need right now).
When I am executing an api using swagger then getting 500 error with message:
can't parse JSON. Raw result:
System.Exception: Method not found: 'Microsoft.Extensions.Logging.ILoggerFactory Microsoft.Extensions.Logging.ConsoleLoggerExtensions.AddConsole(Microsoft.Extensions.Logging.ILoggerFactory, Microsoft.Extensions.Logging.LogLevel)'.
And this is the beginning of stack trace
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.MissingMethodException: Method not found: 'Microsoft.Extensions.Logging.ILoggerFactory Microsoft.Extensions.Logging.ConsoleLoggerExtensions.AddConsole(Microsoft.Extensions.Logging.ILoggerFactory, Microsoft.Extensions.Logging.LogLevel)'.
I am configuring Logger only in Program.cs .
public static IWebHostBuilder CreateWebHostBuilder (string[] args) =>
WebHost.CreateDefaultBuilder (args)
.UseUrls ("http://0.0.0.0:5000")
.ConfigureLogging ((hostingContext, logging) => {
logging.AddConfiguration (hostingContext.Configuration.GetSection ("Logging"));
logging.AddConsole ();
logging.AddApplicationInsights ();
})
.UseStartup<Startup> ();
}
Configurations in appsettings.json
"Logging": {
"IncludeScopes": false,
"ApplicationInsights": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Error"
}
},
"LogLevel": {
"Default": "Information",
"System": "Warning",
"Microsoft": "Warning"
},
"Console": {
"IncludeScopes": true
}
}
I am not understanding why it's not working.
Note: I have 6 APIs in this project and 1 is working successfully with the above changes and 5 are failing with the above error.
As I read in discussion John has given correct suggestion. In visual Studio go to NuGet - Solution and update all the package which has require to update.
I'm using a group of durable functions to do some critical backend logic and orchetration and I would like them to write logs in the same file so I can make a better analysis. Right know my I'm using injected ILog instance with the log.Information method but each function write its own log file.
I'm also using application insights but there is much more information in the files than app insight becauseof the telemetry sampling.
Here is an example of my host.json file
"version": "2.0",
"logging": {
"fileLoggingMode": "always",
"logLevel": {
"default": "Trace",
"Host": "Trace",
"Function": "Trace"
},
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"maxTelemetryItemsPerSecond": 20
}
}
},
Is there a way to have a single log file?
Thanks
How about a logging service that the functions can call? this would solve the problem of concurrent writes as only one service is editing the file. Secondly any new functions can just have the same logic added so it's quicker.
I am looking at the appsettings.json from Serilog sample project, which has the following snippet:
"MinimumLevel": {
"Default": "Debug",
"Override": {
"System": "Information",
"Microsoft": "Information"
}
}
In this context, what is the purpose of Override? The System and Microsoft entries don't have a parent setting in the MinimumLevel node, so what is it overriding?
Unless I am completely misunderstanding the purpose of Override.
By default, you're saying any log entry that is severity "Debug" or higher should be sent to your sink(s) (console, file, etc).
This is similar behavior to Microsoft's document on logging:
For example, logging configuration is commonly provided by the Logging section of app settings files. The following example shows the contents of a typical appsettings.Development.json file:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"Console": {
"IncludeScopes": true
}
}
}
[...]
The LogLevel property under Logging specifies the minimum level to log for selected categories. In the example, System and Microsoft categories log at Information level, and all others log at Debug level.
The override section is for changing that minimum log level for types of a given namespace. In your example that means that a log from a System.* or Microsoft.* namespace must be Information or higher to be shown.
Normally you'd want to see Debug log entries for your code, but a higher level (like Information or Warning) for "not your code", like Microsoft and System.
Instead of putting this configuration in a configuation file you could also use code:
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog((ctx, cfg) =>
{
cfg.ReadFrom.Configuration(ctx.Configuration)
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information);
})
.Build();
Code from kimsereyblog.blogspot.com
Their explanation for the process is:
From the example we saw that we can configure a default minimum level of logging .MinimumLevel.Debug(). We can also override that default for certain namespaces, for example here we set the minimum level of logging for Microsoft namespace to Information. This will prevent ASP.NET Core to log all debug logs while keeping our own debug logs.
Another explanation, from nblumhardt.com:
The first argument of Override is a source context prefix, which is normally matched against the namespace-qualified type name of the class associated with the logger.
...
The effect of the configuration above, then, is to generate events only at or above the Warning level when the logger is owned by a type in a Microsoft.* namespace.
Good day!
I am struggling on how to connect existing database with existing data to my API project. And also how do I know if I'm already connected? I am using .NET Core 1.1 and my database is SQL Server 2012.
appsettings.json :
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS;Database=;User Id=sa;Password=Passw0rd;MultipleActiveResultSets=True"
}
}
}
Startup.cs - ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddDbContext<DefaultConnection>(
options => options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
}
I am following this tutorial but it seems that this creates new database.
http://www.mithunvp.com/aspnet-core-web-api-entity-framework-core/
Would highly appreciate all your comments/solutions/suggestions.
Thank you very much!
You need to add the name of the database into that line :
"DefaultConnection": "Server=COGSOL-LAP13;Database=DATABASENAME;UserId=sa;Password=Passw0rd;MultipleActiveResultSets=True"
And as CodeCaster comment says, you should use the name of the server too
You also have a space between User and Id User Id should be
UserId