Serilog - 在运行时从日志配置中删除丰富器?

问题描述 投票:0回答:1

我有一个 Serilog Enricher,有时会崩溃,因为它正在尝试执行一些可能无法将项目添加到日志条目中的操作。

当发生这种情况时,我当然可以忽略异常。但是,我想在日志中通知发生了这种情况,并从当前配置中删除 Enricher。

最初,我只是想在捕获异常时记录一些内容 - 但随后所有丰富器都对其进行了丰富,包括刚刚尝试记录某些内容的内容。因此,我们得到了一个永远不会解决的无限循环。

为了解决这个问题,我想从 LogContext 中删除 Enricher,以便使用工作丰富器来记录项目,然后不再担心它。

这是我的例子Enricher:

public class PotentiallyCrashingEnricher : ILogEventEnricher
    {
        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            try
            {
                var myString = "Something i want to log"
                property = propertyFactory.CreateProperty("MyProperty", myString);
                logEvent.AddPropertyIfAbsent(property);
                throw new Exception("Oh no...");
            }
            catch (Exception e)
            {
                var oldContext = LogContext.Clone();
                LogContext.Reset();
                Log.ForContext(typeof(PotentiallyCrashingEnricher)).Information($"{e.Message}");
                LogContext.Push(oldContext);
            }
        }
    }

在 catch 块中,您可以看到我尝试的内容 - 但我认为这不应该按照我理解的方式工作。 有没有办法可以做到这一点?

c# serilog
1个回答
0
投票

LoggerConfiguration
是一个构建者,一旦我们调用了
.CreateLogger()
,我们就无法真正做太多改变它。但不用担心,出行并非不可能。


选项 1:重建配置

这可能有点矫枉过正,而且非常不灵活,但它确实满足了您的评论:“我想从 LogContext 中删除 Enricher,以便使用工作丰富器来记录项目,然后不再担心它

由于我们无法删除 Enricher,因此我们将在没有它的情况下重建整个配置。

void BuildLogger(bool enrichWithCrashingThing = true) {
  var cfg = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .WriteTo.Console() 
    //...etc
    ;

  if (enrichWithCrashingThing)
    cfg.Enrich.With<PotentiallyCrashingEnricher>();

  // (Re)create the logger
  Log.Logger = cfg.CreateLogger();
}

// .. On app start
BuildLogger();

在您的 Enricher 中,捕获异常后,只需触发重建即可。

catch (Exception e) {
  BuildLogger(false);
  Log.ForContext(this.GetType()).Error(e, "Enricher has crashed");
}

这将从全局记录器中永远删除 Enricher。


选项 2:条件丰富

这可能是更好的选择。您所需要的只是一个全局标志,并告诉 Serilog 在丰富日志事件时检查它。

var cfg = new LoggerConfiguration()
  .Enrich.FromLogContext()
  .Enrich.When(  // Conditional enrichment only when flagged as ok
    evt => PotentiallyCrashingEnricher.IsOk,
    enrich => enrich.With<PotentiallyCrashingEnricher>()
  )
  .WriteTo.Console()
  //...etc
  ;
Log.Logger = cfg.CreateLogger();

还有带有静态标志的丰富器:

public class PotentiallyCrashingEnricher : ILogEventEnricher 
{
  public static bool IsOk { get; private set; } = true; // Start as OK

  public void Enrich(LogEvent evt, ILogEventPropertyFactory factory) {
    try {
      //...
    }
    catch (Exception e) {
      IsOk = false; // Not OK!
      Log.ForContext(this.GetType()).Error(e, "Enricher has crashed");
      // We can re-enable the enricher again, if desired:
      // IsOk = true;
    }
  }
}

这样,Serilog 将在每次记录事件时检查该标志。

是的,它的效率比“重建后忘记”选项 1 非常轻微低(每个事件的

if
声明的成本极小)。但如果您从未将 IsOk 设置回 true,JIT 最终可能会对其进行优化。

您可以选择重新打开它。

© www.soinside.com 2019 - 2024. All rights reserved.