ELGスタックと互換性のあるフォーマットでファイルにNSpecがunspecific(DataContracts)パラメーターを含む通信データをログに記録するのに数週間も苦労しています。実行時に構成する必要があり、出力パラメーターをMAX文字または深さのように制限できる場合は、これをお勧めします。
NLogには組み込みのJSONシリアライザーがありますが、デフォルトなしでプロパティのみを読み取り、 here を見るとわかるようにフィールドは無視されます。私のデータモデルを適合させることは大きな仕事であり、私はその正しい方法を実際には考えていません。NLogはデータモデルの外観に影響を与えるべきではありません。
カスタムJSONシリアライザー を追加する方法はいくつかあります。
次のように、各クラス(Datacontract)でSetupSerializationを使用できます。
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewRequest>(obj =>
return Newtonsoft.Json.Linq.JToken.FromObject(obj)
)
);
私はすべての通信データをログに記録したいので、データモデル全体を登録する必要があり、その巨大な仕事で効果がありません。
カスタムIValueFormatterを使用することもできますが、通信NLogインスタンスだけに追加することはできません。すべてのロガーにグローバルに追加する必要があります これのように :
NLog.Config.ConfigurationItemFactory.Default.ValueFormatter = new NLogValueFormatter();
したがって、IValueFormatter
は、通信ロガーからのデータのみを操作するようにフィルタリングする必要があります。おそらく、データをどこから取得するかをIValueFormatter
に通知するフラグを使用して、クラスでデータをラップする必要があります。ただし、最適なソリューションのようには思えません。
また、実際にNLogがValueFormatter
フィルターのデータを出力するようにする問題もあります here 。 ValueFormatter
は引き続き実行されますが、ファイルに含まれる通常のNLog JSONデータです。
NLogに必要なのはこれです。
私のデータはIParameterInspectorを介して受信され、パラメーター(型オブジェクト)も保持する特別なCallInformationクラスにコンパイルされます。パラメータは、複数のレイヤーで複雑に変化する可能性があります。 CallInforamtionオブジェクト全体は、次のようにNLogに送信されます。
_comLogger.Log(LogLevel.Info, "ComLogger : {@callInfo}", callInfo);
Nlog.configは現在、次のようになっています。
<logger name="CommunicationLogger" minlevel="Trace" writeto="communicationFileLog"></logger>
<target xsi:type="File"
name="communicationFileLog"
fileName="${basedir}/logs/${shortdate}.log"
maxArchiveDays="5"
maxArchiveFiles="10">
<layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="1">
</layout>
</target>
何が欠けていますか?私のニーズをよりよくサポートできる別のログライブラリはありますか?
私はロルフの提案が最高だと思います-JSON.NETを使用するレイアウトを作成します。フィールドのシリアル化や[JsonIgnore]
の処理など、すべての凝ったトリックを実行できます。
基本的なバージョンは次のようになります。
using System.Collections.Generic;
using Newtonsoft.Json;
using NLog;
using NLog.Config;
using NLog.Layouts;
namespace MyNamespace
{
/// <summary>
/// Render all properties to Json with JSON.NET, also include message and exception
/// </summary>
[Layout("JsonNetLayout")]
[ThreadAgnostic] // different thread, same result
[ThreadSafe]
public class JsonNetLayout : Layout
{
public Formatting Formatting { get; set; } = Formatting.Indented; // This option could be set from the XML config
/// <inheritdoc />
protected override string GetFormattedMessage(LogEventInfo logEvent)
{
var allProperties = logEvent.Properties ?? new Dictionary<object, object>();
allProperties["message"] = logEvent.FormattedMessage;
if (logEvent.Exception != null)
{
allProperties["exception"] = logEvent.Exception.ToString(); //toString to prevent too much data properties
}
return JsonConvert.SerializeObject(allProperties, Formatting);
}
}
}
および レイアウトを登録 、私は使用します:
Layout.Register<JsonNetLayout>("JsonNetLayout"); // namespace NLog.Layouts
必要な設定:
<target xsi:type="File"
name="communicationFileLog"
fileName="${basedir}/logs/${shortdate}.log"
maxArchiveDays="5"
maxArchiveFiles="10">
<layout xsi:type="JsonNetLayout" />
</target>
このオブジェクトをログに記録する場合:
public class ObjectWithFieldsAndJsonStuff
{
[JsonProperty]
private string _myField = "value1";
[JsonProperty("newname")]
public string FieldWithName { get; set; } = "value2";
[JsonIgnore]
public string IgnoreMe { get; set; } = "value3";
}
そして、このロガー呼び出し:
logger
.WithProperty("prop1", "value1")
.WithProperty("prop2", objectWithFieldsAndJsonStuff)
.Info("Hi");
これは次の結果になります:
{
"prop1": "value1",
"prop2": {
"_myField": "value1",
"newname": "value2"
},
"message": "Hi"
}
上記すべての単体テスト-xUnitの使用
[Fact]
public void JsonNetLayoutTest()
{
// Arrange
Layout.Register<JsonNetLayout>("JsonNetLayout");
var xmlConfig = @"
<nlog xmlns=""http://www.nlog-project.org/schemas/NLog.xsd""
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
throwExceptions=""true"">
<targets>
<target xsi:type=""Memory"" name=""target1"" >
<layout xsi:type=""JsonNetLayout"" />
</target>
</targets>
<rules>
<logger name=""*"" minlevel=""Trace"" writeTo=""target1"" />
</rules>
</nlog>
";
LogManager.Configuration = XmlLoggingConfiguration.CreateFromXmlString(xmlConfig);
var logger = LogManager.GetLogger("logger1");
var memoryTarget = LogManager.Configuration.FindTargetByName<MemoryTarget>("target1");
// Act
var objectWithFieldsAndJsonStuff = new ObjectWithFieldsAndJsonStuff();
logger
.WithProperty("prop1", "value1")
.WithProperty("prop2", objectWithFieldsAndJsonStuff)
.Info("Hi");
// Assert
var actual = memoryTarget.Logs.Single();
var expected =
@"{
""prop1"": ""value1"",
""prop2"": {
""_myField"": ""value1"",
""newname"": ""value2""
},
""message"": ""Hi""
}";
Assert.Equal(expected, actual);
}