Logging using SeriLog
Use one of the Nodinite SeriLog sinks with your full framework and .NET Core applications to enable end to end tracking. This feature also includes Microsoft Azure functions built with .NET (usually CSharp).
NuGet package manager example, filtered by Nodinite packages
The following Nodinite Serilog sinks exists:
Sink | Reliable Messaging | GitHub | Nuget |
---|---|---|---|
Log API | GitHub | ||
File (SMB) | GitHub | ||
Azure Service Bus | GitHub | ||
Azure Event Hub | GitHub |
Configuration
You must provide the configuration in either code (explicit) or by using the configuration file appsettings.json
(implicit)
- Code
- Appsettings.json
1. Code
string nodiniteApiUrl = "https://yourenv/nodinite/logapi/";
var settings = new NodiniteLogEventSettings()
{
LogAgentValueId = 42,
EndPointDirection = 0,
EndPointTypeId = 0,
EndPointUri = "Nodinite.Serilog.ApiSink.Tests.Serilog",
EndPointName = "Nodinite.Serilog.ApiSink.Tests",
ProcessingUser = "NODINITE",
ProcessName = "Nodinite.Serilog.LogApiSink.Tests",
ProcessingMachineName = "NODINITE-DEV",
ProcessingModuleName = "DOTNETCORE.TESTS",
ProcessingModuleType = "DOTNETCORE.TESTPROJECT"
};
ILogger log = new LoggerConfiguration()
.WriteTo.NodiniteApiSink(nodiniteApiUrl, settings)
.CreateLogger();
2. Appsettings.json
{
"Serilog": {
"Using": [ "Nodinite.Serilog.Apisink" ],
"WriteTo": [
{
"Name": "NodiniteApiSink",
"Args": {
"NodiniteApiUrl": "",
"Settings": {
"LogAgentValueId": 42,
"EndPointName": "Nodinite.Serilog.ApiSink.Tests",
"EndPointUri": "Nodinite.Serilog.ApiSink.Tests.Serilog",
"EndPointDirection": 0,
"EndPointTypeId": 86,
"OriginalMessageTypeName": "https://ACME.com/Customers/1.0#Batch",
"ProcessingUser": "NODINITE",
"ProcessName": "Nodinite.Serilog.ApiSink.Tests",
"ProcessingMachineName": "NODINITE-DEV",
"ProcessingModuleName": "DOTNETCORE.TESTS",
"ProcessingModuleType": "DOTNETCORE.TESTPROJECT"
}
}
}
]
}
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Logger log = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
1. Code
var folder = "{Your Folder}";
var settings = new NodiniteLogEventSettings()
{
LogAgentValueId = 42,
EndPointDirection = 0,
EndPointTypeId = 0,
EndPointUri = "Nodinite.Serilog.FileSink.Tests.Serilog",
EndPointName = "Nodinite.Serilog.FileSink.Tests",
ProcessingUser = "NODINITE",
ProcessName = "Nodinite.Serilog.FileSink.Tests",
ProcessingMachineName = "NODINITE-DEV",
ProcessingModuleName = "DOTNETCORE.TESTS",
ProcessingModuleType = "DOTNETCORE.TESTPROJECT"
};
ILogger log = new LoggerConfiguration()
.WriteTo.NodiniteFileSink(folder, settings)
.CreateLogger();
2. Appsettings.json
{
"Serilog": {
"Using": [ "Nodinite.Serilog.FileSink" ],
"WriteTo": [
{
"Name": "NodiniteFileSink",
"Args": {
"Folder": "",
"Settings": {
"LogAgentValueId": 42,
"EndPointName": "Nodinite.Serilog.FileSink.Tests",
"EndPointUri": "Nodinite.Serilog.FileSink.Tests.Serilog",
"EndPointDirection": 0,
"EndPointTypeId": 86,
"OriginalMessageTypeName": "https://ACME.com/Customers/1.0#Batch",
"ProcessingUser": "NODINITE",
"ProcessName": "Nodinite.Serilog.FileSink.Tests",
"ProcessingMachineName": "NODINITE-DEV",
"ProcessingModuleName": "DOTNETCORE.TESTS",
"ProcessingModuleType": "DOTNETCORE.TESTPROJECT"
}
}
}
]
}
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Logger log = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
1. Code
var connectionString = "{Your ServiceBus Connection String";
var queueName = "{Your ServiceBus Queue Name}";
var settings = new NodiniteLogEventSettings()
{
LogAgentValueId = 42,
EndPointDirection = 0,
EndPointTypeId = 0,
EndPointUri = "Nodinite.Serilog.ServiceBusSink.Tests.Serilog",
EndPointName = "Nodinite.Serilog.ServiceBusSink.Tests",
ProcessingUser = "NODINITE",
ProcessName = "Nodinite.Serilog.ServiceBusSink.Tests",
ProcessingMachineName = "NODINITE-DEV",
ProcessingModuleName = "DOTNETCORE.TESTS",
ProcessingModuleType = "DOTNETCORE.TESTPROJECT"
};
ILogger log = new LoggerConfiguration()
.WriteTo.NodiniteServiceBusSink(connectionString, queueName, settings)
.CreateLogger();
2. Appsettings.json
{
"Serilog": {
"Using": [ "Nodinite.Serilog.ServiceBusSink" ],
"WriteTo": [
{
"Name": "NodiniteServiceBusSink",
"Args": {
"ConnectionString": "",
"QueueName": "",
"Settings": {
"LogAgentValueId": 42,
"EndPointName": "Nodinite.Serilog.ServiceBusSink.Tests",
"EndPointUri": "Nodinite.Serilog.ServiceBusSink.Tests.Serilog",
"EndPointDirection": 0,
"EndPointTypeId": 86,
"OriginalMessageTypeName": "https://ACME.com/Customers/1.0#Batch",
"ProcessingUser": "NODINITE",
"ProcessName": "Nodinite.Serilog.ServiceBusSink.Tests",
"ProcessingMachineName": "NODINITE-DEV",
"ProcessingModuleName": "DOTNETCORE.TESTS",
"ProcessingModuleType": "DOTNETCORE.TESTPROJECT"
}
}
}
]
}
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Logger log = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
1. Code
var connectionString = "{Your EventHub Connection String";
var settings = new NodiniteLogEventSettings()
{
LogAgentValueId = 42,
EndPointDirection = 0,
EndPointTypeId = 0,
EndPointUri = "Nodinite.Serilog.EventHubSink.Tests.Serilog",
EndPointName = "Nodinite.Serilog.EventHubSink.Tests",
ProcessingUser = "NODINITE",
ProcessName = "Nodinite.Serilog.EventHubSink.Tests",
ProcessingMachineName = "NODINITE-DEV",
ProcessingModuleName = "DOTNETCORE.TESTS",
ProcessingModuleType = "DOTNETCORE.TESTPROJECT"
};
ILogger log = new LoggerConfiguration()
.WriteTo.NodiniteEventHubSink(connectionString, settings)
.CreateLogger();
2. Appsettings.json
{
"Serilog": {
"Using": [ "Nodinite.Serilog.EventHubSink" ],
"WriteTo": [
{
"Name": "NodiniteEventHubSink",
"Args": {
"ConnectionString": "",
"Settings": {
"LogAgentValueId": 42,
"EndPointName": "Nodinite.Serilog.EventHubSink.Tests",
"EndPointUri": "Nodinite.Serilog.EventHubSink.Tests.Serilog",
"EndPointDirection": 0,
"EndPointTypeId": 86,
"OriginalMessageTypeName": "https://ACME.com/Customers/1.0#Batch",
"ProcessingUser": "NODINITE",
"ProcessName": "Nodinite.Serilog.EventHubSink.Tests",
"ProcessingMachineName": "NODINITE-DEV",
"ProcessingModuleName": "DOTNETCORE.TESTS",
"ProcessingModuleType": "DOTNETCORE.TESTPROJECT"
}
}
}
]
}
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Logger log = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Logging
Microsoft.Extensions.Primitives.StringValues id;
req.Headers.TryGetValue("x-ms-client-tracking-id", out id);
Serilog.ILogger log = new LoggerConfiguration()
.WriteTo.NodiniteEventHubSink(connectionString, settings)
.Enrich.WithProperty("Color", "Blue")
.CreateLogger()
.ForContext("ApplicationInterchangeId", id[0])
.ForContext("body", "{\"Order\": {...");
log.Information("Order '12' has been imported.");
simple code example
Please review the Pickup Service for additional information.
Log Event
The Nodinite SeriLog sink produces a Nodinite JSON Log Event.
The JSON Log Event has three distinct parts:
- Event details (also named Additional field values within Nodinite)
- Payload (Body, 0 or more)
- Context properties (Key/Value)
LogDateTime = 2018-05-03 13:37:00+02:00
EndPointName = https://api.nodinite.com/...
MessageType=Invoice
...] end subgraph "2. Payload" ro[fal:fa-envelope Message
Body=base64EncodedMessage] end subgraph "3. Context Properties" roKey[fal:fa-key Key Values
InvoiceNo = 123
CorrelationId=456
...] end end
1. Details
The following mandatory fields must be set on the Nodinite class either in configuration or with code:
Mandatory | Data Type | Field | Value | Comment |
---|---|---|---|---|
number |
LogAgentValueId | 42 | Who (Log Agents) sent the data | |
string |
EndPointName | "Nodinite.Serilog.ApiSink.Tests" | Name of Endpoint transport | |
string |
EndPointUri | "https://sampleazurefunction1337.azurewebsites.net/api/HttpTrigger1" | URI for Endpoint transport | |
number |
EndPointDirection | 10 (Two-way receive) | Direction for Endpoint transport | |
number |
EndPointTypeId | 86 (HTTPS) | Type of Endpoint transport | |
string |
OriginalMessageTypeName | "https://ACME.com/Customers/1.0#Batch" | Message Type Name |
Note: The specified values are only examples
Review the JSON Log Event user guide for details about the optional fields.
2. Payload
If you want to log the payload (body), then please add it as plain text in the context property ("body").
3. Context Properties
The following optional coded context properties are mapped if present to the following Nodinite "additional field values":
Context Key | Description | |
---|---|---|
body | Plain text | The Nodinite SeriLog sink internally adds this to the optional Body field |
OriginalMessageTypeName | Name of MessageType, if not set, the default value is https://ACME.com/Customers/1.0#Batch |
|
ApplicationInterchangeId | Please re-use if possible a scenario wide id, for example the x-ms-client-tracking-id in Azure |
Review the Context Options user guide for additional features overriding the default behaviour.
Automatically assigned
The following properties are automatically assigned by the Nodinite SeriLog sink:
Field | Description | Example |
---|---|---|
ServiceInstanceActivityId | A guid unique for each log event | ee2daba2-4807-4ad8-1337-620e2b9c0052 |
LocalInterchangeId | A unique re-used guid set on all logged events within one class instance | ff2daba2-4807-4ad8-1337-620e2b9c0053 |
LogDateTime | UTC | 2020-05-17T13:37:42.001+01:00 |
LogText | The text to log | Hello World |
Log Status Code | The user defined Log Status Code for the logged event | Review the 'Log Status Code translation table' on this page. |
Log Status Code translation table
The Nodinite Log Status Codes are translated as described in the table below from the following SeriLog Log Levels:
SeriLog Log Level | Nodinite Log Status Code | Nodinite Log Status | Code example |
---|---|---|---|
Debug | 0 | None | log.Debug |
Info | 0 | None | log.Information |
Verbose | 0 | None | log.Verbose |
Error | -1 | Error | log.Error |
Fatal | -2 | Fatal | log.Fatal |
Warning | 1 | Warning | log.Warning |
.NET Exceptions
New 1.3.0
If you log an Exception, for example using the LogError(
method, the Nodinite sink adds it to the Context. The name of the Context key is ExtendedProperties/1.0#Exception.
From Nodinite, you can then use the Formula plugin to create Search Fields and extract whatever piece of information you seek from the Exception.
Example extracting the Message part of an exception.
JsonPath('..Message', Context('ExtendedProperties/1.0#Exception'))
The Exception can host any number of inner exceptions.