Serilog 访问传递给日志语句的 LogEvent 中的原始对象
Serilog access original object in LogEvent that was passed to logging statement
我在 Unity3D 中使用 Serilog。
我有一个简单的接收器,它将 Serilog 日志记录语句写入 Unity 的 Debug.LogFormat
:
public class UnityLogEventSink : ILogEventSink
{
public void Emit(LogEvent logEvent)
{
// QUESTION: How to pass a UnityEngine.Object to Serilog logging statement such that it is available here?
UnityEngine.Object contextObject = null;
using (StringWriter stringBuffer = new StringWriter())
{
GetTextFormatter().Format(logEvent, stringBuffer);
LogType logType = GetUnityLogType(logEvent);
string logString = stringBuffer.ToString().Trim();
Debug.LogFormat(logType, LogOption.NoStacktrace, contextObject, logString);
}
}
// GetTextFormatter, GetUnityLogType etc. are defined here ...
}
现在我想将一个游戏对象传递给 Serilog 日志记录语句,这样我就可以在我的接收器中访问这个游戏对象。 (使用 GameObject 调用 Debug.LogFormat
将在单击日志消息时在 Unity 编辑器中突出显示该对象。我想要那个。)
// Example what I have in mind (not working):
logger.ForContext("unityObject", gameObject).Information("This is an info with context");
我尝试将 GameObject 包装在 ScalarValue 和自定义 LogEventPropertyValue 中,但 GameObject 仍被转换为字符串(发生在 Serilog 的 PropertyValueConverter.cs 中)。
我需要 Debug.LogFormat 的原始 GameObject 实例。
有没有办法保留 GameObject 引用以便我可以在我的接收器中使用它?
作为解决方法,我可以将引用存储在静态地图中,并使用地图的键记录一个字符串 属性。这样我就可以稍后在接收器中从该地图中获取实例。但这是围绕 Serilog 工作的。
有没有更好的利用 Serilog 的解决方案?
Nick 在 https://github.com/serilog/serilog/issues/1124
中为我回答了这个问题
public class ScalarValueEnricher : ILogEventEnricher
{
protected readonly LogEventProperty _prop;
public ScalarValueEnricher(string name, object value)
{
_prop = new LogEventProperty(name, new ScalarValue(value));
}
public void Enrich(LogEvent evt, ILogEventPropertyFactory _) =>
evt.AddPropertyIfAbsent(_prop);
}
(Here it is in context, in F#)
也可以创建一个 Unity 特定的子类:
public class UnityObjectEnricher : ScalarValueEnricher
{
public static readonly string unityObjectPropertyName = "unityObject";
public UnityObjectEnricher(UnityEngine.Object value)
: base(unityObjectPropertyName, value)
{
}
}
然后可以在接收器中访问此 属性:
private UnityEngine.Object GetUnityEngineContextObject(LogEvent logEvent)
{
if (logEvent.Properties.TryGetValue(UnityObjectEnricher.unityObjectPropertyName, out LogEventPropertyValue logEventPropertyValue))
{
if (logEventPropertyValue is ScalarValue scalarValue)
return scalarValue.Value as UnityEngine.Object;
}
return null;
}
像这样使用它:
// Note: using LogContext requires Serilog configuration ".Enrich.FromLogContext()"
using (LogContext.Push(new UnityObjectEnricher(gameObject)))
{
logger.Information("This is an info with context");
}
或者:
logger.ForContext(new UnityObjectEnricher(gameObject)).Information("This is another info with context");
我在 Unity3D 中使用 Serilog。
我有一个简单的接收器,它将 Serilog 日志记录语句写入 Unity 的 Debug.LogFormat
:
public class UnityLogEventSink : ILogEventSink
{
public void Emit(LogEvent logEvent)
{
// QUESTION: How to pass a UnityEngine.Object to Serilog logging statement such that it is available here?
UnityEngine.Object contextObject = null;
using (StringWriter stringBuffer = new StringWriter())
{
GetTextFormatter().Format(logEvent, stringBuffer);
LogType logType = GetUnityLogType(logEvent);
string logString = stringBuffer.ToString().Trim();
Debug.LogFormat(logType, LogOption.NoStacktrace, contextObject, logString);
}
}
// GetTextFormatter, GetUnityLogType etc. are defined here ...
}
现在我想将一个游戏对象传递给 Serilog 日志记录语句,这样我就可以在我的接收器中访问这个游戏对象。 (使用 GameObject 调用 Debug.LogFormat
将在单击日志消息时在 Unity 编辑器中突出显示该对象。我想要那个。)
// Example what I have in mind (not working):
logger.ForContext("unityObject", gameObject).Information("This is an info with context");
我尝试将 GameObject 包装在 ScalarValue 和自定义 LogEventPropertyValue 中,但 GameObject 仍被转换为字符串(发生在 Serilog 的 PropertyValueConverter.cs 中)。
我需要 Debug.LogFormat 的原始 GameObject 实例。 有没有办法保留 GameObject 引用以便我可以在我的接收器中使用它?
作为解决方法,我可以将引用存储在静态地图中,并使用地图的键记录一个字符串 属性。这样我就可以稍后在接收器中从该地图中获取实例。但这是围绕 Serilog 工作的。 有没有更好的利用 Serilog 的解决方案?
Nick 在 https://github.com/serilog/serilog/issues/1124
中为我回答了这个问题public class ScalarValueEnricher : ILogEventEnricher
{
protected readonly LogEventProperty _prop;
public ScalarValueEnricher(string name, object value)
{
_prop = new LogEventProperty(name, new ScalarValue(value));
}
public void Enrich(LogEvent evt, ILogEventPropertyFactory _) =>
evt.AddPropertyIfAbsent(_prop);
}
(Here it is in context, in F#)
也可以创建一个 Unity 特定的子类:
public class UnityObjectEnricher : ScalarValueEnricher
{
public static readonly string unityObjectPropertyName = "unityObject";
public UnityObjectEnricher(UnityEngine.Object value)
: base(unityObjectPropertyName, value)
{
}
}
然后可以在接收器中访问此 属性:
private UnityEngine.Object GetUnityEngineContextObject(LogEvent logEvent)
{
if (logEvent.Properties.TryGetValue(UnityObjectEnricher.unityObjectPropertyName, out LogEventPropertyValue logEventPropertyValue))
{
if (logEventPropertyValue is ScalarValue scalarValue)
return scalarValue.Value as UnityEngine.Object;
}
return null;
}
像这样使用它:
// Note: using LogContext requires Serilog configuration ".Enrich.FromLogContext()"
using (LogContext.Push(new UnityObjectEnricher(gameObject)))
{
logger.Information("This is an info with context");
}
或者:
logger.ForContext(new UnityObjectEnricher(gameObject)).Information("This is another info with context");