3

アーカイブを使用してログ ファイルの数を制限し、アーカイブされた各ログのファイル名をログの元の日付にしたいと考えています。十分に単純です。

これは私の目標の 1 つです。

<target xsi:type="File" name="info" fileName="${basedir}/logs/info.log"
        layout="${date:format=HH\:mm\:ss}&#009;|&#009;${uppercase:${level}}&#009;|&#009;${message}"
        archiveEvery="Day"
        archiveFileName="${basedir}/logs/archive/info/${shortdate}.{#}.log"
        archiveNumbering="Rolling"
        maxArchiveFiles="30"/>

archiveFileName に {#} を含める必要があることを読みました。そうしないと、ファイル名に日付が含まれているとアーカイブがまったく機能しません。

ただし、アーカイブは日付が変更された後に実行されるため、${shortdate} は常に新しい日付、つまり希望の日付から 1 日 (またはそれ以上) 後の日付になります。メッセージが 2013 年 6 月 12 日の今日ログに記録された場合、明日アーカイブされると、2013-06-13.log という名前のファイルに配置されます。

正しい日付を取得する方法はありますか?誰かが変数を提案しているのを見たことがありますが、それがどのように機能するかわかりません...これは、非常に明白な機能のように思えます。これは間違いなくアーカイブのナンバリング モードの 1 つである必要があります。現在利用可能な番号付けモードは、日付に比べて非常に実用的ではないようです。

この質問は、Delete log files after x daysに関連しています。アーカイブ機能を使用せずにログ ファイルの最大数を設定することができた場合 (アーカイブ機能に実際に必要なため)、{#} も使用する必要がないため、実際にはさらに優れていますが、それはありえないと思います。

4

2 に答える 2

1

NLog は、この質問を投稿して以来、まさに私が探していた番号形式「日付」を追加しました。

詳細については、 https://github.com/nlog/NLog/wiki/File-target#archival-optionsを参照してください。

于 2015-10-23T14:18:35.663 に答える
0

これは一種のRube Goldbergアプローチと見なされるかもしれませんが、うまくいくかもしれません...「前の」日付を計算するカスタム LayoutRenderer を作成できます。この LayoutRenderer のパラメーターは、Target 構成の「archiveEvery」設定になります。

ShortDateLayoutRenderer を基礎として使用する...

(NLogのgitリポジトリから取得...)

[LayoutRenderer("shortdate")]
[ThreadAgnostic]
public class ShortDateLayoutRenderer : LayoutRenderer
{
    /// <summary>
    /// Gets or sets a value indicating whether to output UTC time instead of local time.
    /// </summary>
    /// <docgen category='Rendering Options' order='10' />
    [DefaultValue(false)]
    public bool UniversalTime { get; set; }

    /// <summary>
    /// Renders the current short date string (yyyy-MM-dd) and appends it to the specified <see cref="StringBuilder" />.
    /// </summary>
    /// <param name="builder">The <see cref="StringBuilder"/> to append the rendered data to.</param>
    /// <param name="logEvent">Logging event.</param>
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        var ts = logEvent.TimeStamp;
        if (this.UniversalTime)
        {
            ts = ts.ToUniversalTime();
        }

        builder.Append(ts.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
    }
}

PreviousDateLayoutRenderer は次のようになります (このコードをコンパイルもテストもしていませんが、以前に LayoutRenderers を書いたことがあることに注意してください)。

[LayoutRenderer("previousdate")]
[ThreadAgnostic]
public class PreviousDateLayoutRenderer : LayoutRenderer
{
    /// <summary>
    /// Gets or sets a value indicating whether to output UTC time instead of local time.
    /// </summary>
    /// <docgen category='Rendering Options' order='10' />
    [DefaultValue(false)]
    public bool UniversalTime { get; set; }

    /// <summary>
    /// Gets or sets the value indicating the unit of time to subtract to get previous date.
    /// </summary>
    [DefaultValue("Day")]
    public string TimeUnit { get; set; }

    /// <summary>
    /// Gets the current date, subtracts one TimeUnit, renders the resulting short date string,
    /// then appends it to the specified <see cref="StringBuilder" />.
    /// </summary>
    /// <param name="builder">The <see cref="StringBuilder"/> to append the rendered data to.</param>
    /// <param name="logEvent">Logging event.</param>
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        var ts = logEvent.TimeStamp;
        if (this.UniversalTime)
        {
            ts = ts.ToUniversalTime();
        }

        // This could certainly be better.  Probably smarter to put code in the setter of the
        // TimeUnit property to compute a TimeSpan member variable that could then be subtracted
        // in this method rather than check the TimeUnit and compute the TimeSpan every time.

        TimeSpan span;

        switch (TimeUnit)
        {
          case "Day":
            span = TimeSpan.FromDays(1);
            break;
          case "Hour":
            span = TimeSpan.FromHours(1);
            break;
        }

        ts -= span;

        builder.Append(ts.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
    }
}

または、非常によく似たロジックを適用する LayoutRendererWrapper を作成することもできますが、(ラッパーが日付として解釈しようとする) 文字列が渡され、そこから目的の TimeSpan が差し引かれます。

上で簡単に説明したラッパーが与えられた場合、次のように構成できます。

<target xsi:type="File" name="info" fileName="${basedir}/logs/info.log"
        layout="${date:format=HH\:mm\:ss}&#009;|&#009;${uppercase:${level}}&#009;|&#009;${message}"
        archiveEvery="Day"
        archiveFileName="${basedir}/logs/archive/info/${previousdate{shortdate,"Day"}}.{#}.log"
        archiveNumbering="Rolling"
        maxArchiveFiles="30"/>

私の提案では、アーカイブされたファイルには、現在の日付までの「前の日付」に基づいて名前を付ける必要があると想定しています。また、ファイルが日付の変更時にロールされるという上記の事実にも依存します。したがって、「前の」日付ではなく「現在の」日付がファイル名に割り当てられます。確かに、このアプローチでは期待どおりの結果が得られない場合があります。アプリケーションが平日のみ実行される場合はどうなりますか? 月曜日に終日実行され、火曜日に最初のログが記録され、ログ ファイルがローリングされ、前日 (月曜日) の日付に基づいて名前が付けられます。それは結構です。残りの週、つまり週末までは問題ありません。プログラムが金曜日に実行されると、ログが取得されます。プログラムは週末には実行されません。月曜日に初めてメッセージがログに記録され、ログ ファイルはロールされます。この場合、前の日付は日曜日ですが、おそらく前の日付を金曜日にしたいと思います。何らかの理由で、特定の日のログがない場合もあります。翌日、ロールオーバーの原因となるログがあります。繰り返しますが、ここで説明するアプローチでは、前の日付が実際の「物理的な」前日であると判断されます。「ログが書き込まれた」前日を意味するよりも「前」を好む場合があります。

これはちょっと長くなりましたが、役に立つかもしれません。

于 2013-06-12T18:29:37.973 に答える