10

I am currently trying to change our system configuration to work with Serilog (instead of working with FileBeat as a shipper to LogStash)

We are also working with the log type field (which is easy to configure in the FileBeat config file) in our various queries and for indexing out logs on Elastic.

The problem is that when using Serilog we get the default type logevent, and I didn't find where I can configure it. I want to have an option to determine a specific log type per Serilog instance. At the moment I have the default type for all of my logs.

my Serilop Config is:

        var path = GetLogPath();
        var logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .Enrich.WithMachineName()
            .Enrich.WithProperty("RequestId", Guid.NewGuid())
            .WriteTo.RollingFile(
                pathFormat: path,
                outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u4}] [{RequestId}] {Message}{NewLine}{Exception}", buffered: false, shared: true);
        logger.WriteTo.Elasticsearch(
                new ElasticsearchSinkOptions(new Uri(this.configurationService.ElasticSearchUrl())));

How can I change the log type?

EDIT

After some investigation, I found out I suppose to change the typeName filed in the LoggerConfiguration and seem that I can do so only through the AppConfig file, which again event if I will change it, the change will affect all the logger instances.

Do I miss something?

Green
  • 2,405
  • 3
  • 22
  • 46
  • more info about what `type` means to you. In general, in Serilog, there is a `{SourceContext}` property you can put in as a token into the emit format if you mean the type associated with the logger. if you mean an id for the message template, https://github.com/serilog/serilog-formatting-compact will give you clues. (I know zero about the ES sink (obviously) but if you emit json, you can normally use the format to guid what to include) – Ruben Bartelink May 08 '18 at 18:32
  • 1
    thanx Ruben, I did some reading about this property and it indeed sounds like good practice. I'm not sure if it will come hand to hand with my problem that related for the log indexing in the Eleastic – Green May 13 '18 at 08:03

3 Answers3

4

Updated Answer

To add Properties and values to your logger, you can use Contextual logging and Enrichment

Contextual Logger

The simplest and most direct way to attach contextual properties to a log event

First initialized your logger:

Log.Logger = new LoggerConfiguration().ReadFrom.AppSettings().CreateLogger();

Then you can create your contextual logger:

// adding Log Context
var StudentLogger = Log.Logger.ForContext<Student>();

StudentLogger.Error(/* log message */);

Or you can use correlation log entries:

// correlation Log Entries
var orderId = "some value";
var corrLog = Log.Logger.ForContext("orderId", orderId)

corrLog.Error(/* log message */);

Enrichment

In some cases we would like every event created by a logger to carry the same, fixed, property value. The Application example is one of these.

Serilog provides Enrich.WithProperty() at the level of a LoggerConfiguration for this:

Log.Logger = new LoggerConfiguration()
    .Enrich.WithProperty("Application", "e-Commerce")
    .Enrich.WithProperty("Environment", ConfigurationManager.AppSettings["Environment"])
    // Other logger configuration

Original Answer

There are two ways to configure Serilog:

Using API (need serilog.sinks.elasticsearch package):

var loggerConfig = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200") ){
         AutoRegisterTemplate = true,
 });
var logger = loggerConfig.CreateLogger();

Serilog Documentation

Using configuration from AppSettings (need Serilog.Settings.AppSettings in addition to serilog.sinks.elasticsearch)

This way, you put all of your setting in AppSetting file, e.g.

<appSettings>
    <add key="serilog:using" value="Serilog.Sinks.Elasticsearch"/>
    <add key="serilog:write-to:Elasticsearch.nodeUris" value="http://localhost:9200;http://remotehost:9200"/>
    <add key="serilog:write-to:Elasticsearch.indexFormat" value="custom-index-{0:yyyy.MM}"/>
    <add key="serilog:write-to:Elasticsearch.templateName" value="myCustomTemplate"/>
  </appSettings>

And tell serilog to read the config from appSettigns

Log.Logger = new LoggerConfiguration()
  .ReadFrom.AppSettings()
  ... // Other configuration here, then
  .CreateLogger()

See: AppSetting and ElasticSearch Configure Sink

I am not sure which log event type you are referring to? In my case, I pass the object type while logging the errors:

catch (Exception ex)
{
    Logger.Error(ex, string.Format("Exception occured in Controller: {0}, Action: Post.", this.GetType()), this.GetType());
Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
  • thank you for the detailed answer, It indeed sounds like the way to change the **typeName** field. But, as I mentioned in my EDIT, if I have several different types of logs in different classes (let say class A writes a LogA type log and the class B Writes a LogB and so on) how can I configure each of them differently if I use the same config file? Can I somehow use different config files to different classes – Green May 13 '18 at 11:08
  • this might help: https://github.com/serilog/serilog/blob/dev/src/Serilog/Log.cs#L115-L118 – Hooman Bahreini May 13 '18 at 11:19
  • The problem that the Elastic is working with indexing. There for, if want to continue to work as before (which I do, from convenient reasons) I need to change the type. From the reason that the indexing in elastic is based on that filed. I am thinking just to fork from the current repository and add this functionality myself. but m pretty sure there as to be a way that I missed – Green May 13 '18 at 11:24
4

Just use another overload for the Elasticsearch sink:

var path = GetLogPath();
var logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .Enrich.WithMachineName()
    .Enrich.WithProperty("RequestId", Guid.NewGuid())
    .WriteTo.RollingFile(
        pathFormat: path,
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u4}] [{RequestId}] {Message}{NewLine}{Exception}", buffered: false, shared: true);
logger.WriteTo.Elasticsearch(
        this.configurationService.ElasticSearchUrl(), typeName: "type");

so you don't have to specify the typeName in the appsettings and it also won't affect all instances.

Manuel Allenspach
  • 12,467
  • 14
  • 54
  • 76
  • doesn't compile...the Elasticsearch constructor doesn't accept this overload.only that: `public static LoggerConfiguration Elasticsearch(this LoggerSinkConfiguration loggerSinkConfiguration, string nodeUris, string indexFormat = null, string templateName = null);` – Green May 14 '18 at 09:16
  • 1
    @Green Do you have an older version of the Elasticsearch sink? I tried v6.5.0 of `Serilog.Sinks.ElasticSearch`, which exposes the new method. – Manuel Allenspach May 14 '18 at 10:16
  • Yes, I saw it just now, I updated my version to the 6.5 - indeed they ad this functionality. cool dude, thanks! P.S I had to give another parameter (for example: `serializer` ) , if not, the compiler will complain on ambiguity with the 2 constructors they added) – Green May 14 '18 at 11:31
0

An alternative option would be to create a global loader static class. Define multiple ILogger fields, one for error, another for diagnostic and so forth. Configure the fields inside the static constructor. Then create several public methods, WriteError(), WriteDebug(), WriteInfo() and so forth. You will be able to decide the LogEventLevel when calling the ILogger.Write(LogEventLevel.Debug, logDetail) from WriteDebug(logDetail) method for instance.

Houssam Hamdan
  • 888
  • 6
  • 15