Sitecore Custom Log,如何每天只写一个文件?

Sitecore Custom Log, how to write only one file per day?

我们实现了自定义日志并写入自定义日志文件。 问题是,日志每天创建几次,文件名如下:

MyCustom.log.20161208.165109
MyCustom.log.20161208.165845
MyCustom.log.20161208.175134
MyCustom.log.20161208.184432

定义是这样的:

    <appender name="MyCustomLogAppender" type="log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging">
  <file value="$(dataFolder)/logs/MyCustom.log.{date}.txt" />
  <appendToFile value="true" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n" />
  </layout>
  <encoding value="utf-8" />
</appender>

谁能告诉我我需要配置什么才能每天只接收一个文件?或者换句话说,什么时候创建新文件?

如果您覆盖 SitecoreLogFileAppender 的标准行为并创建一个从 FileAppender 继承的新 CustomLogFileAppender class,您可以轻松解决这个问题。不幸的是,SitecoreLogFileAppender 没有为您提供仅覆盖您需要根据您的要求进行修改的特定方法的可能性。因此,您需要将所有代码从 SitecoreLogFileAppender 复制到新创建的文件附加程序中。

namespace MyProject.Core
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Web;
    using log4net.Appender;
    using log4net.spi;

    /// <summary>
    /// Custom log file appender
    /// </summary> 
    public class CustomLogFileAppender : FileAppender
    {
        /// <summary>
        /// The m_current date
        /// </summary>
        private DateTime m_currentDate;

        /// <summary>
        /// The m_original file name
        /// </summary>
        private string m_originalFileName;

        /// <summary>
        /// Initializes a new instance of the <see cref="CustomLogFileAppender"/> class.
        /// </summary>
        public CustomLogFileAppender()
        {
            this.m_currentDate = DateTime.Now;
        }

        /// <summary>
        /// Gets or sets the file.
        /// </summary>
        /// <value>
        /// The file.
        /// </value>
        public override string File
        {
            get
            {
                return base.File;
            }

            set
            {
                if (this.m_originalFileName == null)
                {
                    string str = value;
                    Dictionary<string, string> variables = ConfigReader.GetVariables();
                    foreach (string index in variables.Keys)
                    {
                        string oldValue = "$(" + index + ")";
                        str = str.Replace(oldValue, variables[index]);
                    }

                    this.m_originalFileName = this.MapPath(str.Trim());
                }

                base.File = this.m_originalFileName;
            }
        }

        /// <summary>
        /// Makes the path.
        /// </summary>
        /// <param name="part1">The part1.</param>
        /// <param name="part2">The part2.</param>
        /// <param name="separator">The separator.</param>
        /// <returns>
        /// Complete path.
        /// </returns>
        public static string MakePath(string part1, string part2, char separator)
        {
            if (string.IsNullOrEmpty(part1))
            {
                return part2 ?? string.Empty;
            }

            if (string.IsNullOrEmpty(part2))
            {
                return part1 ?? string.Empty;
            }

            if ((int)part1[part1.Length - 1] == (int)separator)
            {
                part1 = part1.Substring(0, part1.Length - 1);
            }

            if ((int)part2[0] == (int)separator)
            {
                part2 = part2.Substring(1);
            }

            return part1 + (object)separator + part2;
        }

        /// <summary>
        /// Appends the specified logging event.
        /// </summary>
        /// <param name="loggingEvent">The logging event.</param>
        protected override void Append(LoggingEvent loggingEvent)
        {
            DateTime now = DateTime.Now;
            if (this.m_currentDate.Day != now.Day || this.m_currentDate.Month != now.Month || this.m_currentDate.Year != now.Year)
            {
                lock (this)
                {
                    this.CloseFile();
                    this.m_currentDate = DateTime.Now;
                    this.OpenFile(string.Empty, false);
                }
            }

            base.Append(loggingEvent);
        }

        /// <summary>
        /// Opens the file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="append">if set to <c>true</c> [append].</param>
        protected override void OpenFile(string fileName, bool append)
        {
            fileName = this.m_originalFileName;
            fileName = fileName.Replace("{date}", this.m_currentDate.ToString("yyyyMMdd"));
            fileName = fileName.Replace("{time}", this.m_currentDate.ToString("HHmmss"));
            fileName = fileName.Replace("{processid}", CustomLogFileAppender.GetCurrentProcessId().ToString());

            base.OpenFile(fileName, append);
        }

        /// <summary>
        /// Gets the current process identifier.
        /// </summary>
        /// <returns>
        /// The process Id.
        /// </returns>
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int GetCurrentProcessId();

        /// <summary>
        /// Gets the name of the timed file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns>
        /// Filename with timestamp.
        /// </returns>
        private string GetTimedFileName(string fileName)
        {
            int num = fileName.LastIndexOf('.');
            if (num < 0)
            {
                return fileName;
            }

            return
                string.Concat(
                    new object[4]
                        {
                            (object)fileName.Substring(0, num), (object)'.', (object)this.m_currentDate.ToString("HHmmss"),
                            (object)fileName.Substring(num)
                        });
        }

        /// <summary>
        /// Determines whether the specified file name is locked.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns>
        /// Locked or not.
        /// </returns>
        private bool IsLocked(string fileName)
        {
            if (!System.IO.File.Exists(fileName))
            {
                return false;
            }

            try
            {
                FileStream fileStream = System.IO.File.OpenWrite(fileName);
                if (fileStream == null)
                {
                    return true;
                }

                fileStream.Close();
                return false;
            }
            catch (Exception ex)
            {
                string message = ex.Message;
                return true;
            }
        }

        /// <summary>
        /// Maps the path.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns>
        /// Mapped path.
        /// </returns>
        private string MapPath(string fileName)
        {
            if (fileName == string.Empty || fileName.IndexOf(":/", System.StringComparison.Ordinal) >= 0 || fileName.IndexOf("://", System.StringComparison.Ordinal) >= 0)
            {
                return fileName;
            }

            var index = fileName.IndexOfAny(new char[2] { '\', '/' });
            if (index >= 0 && (int)fileName[index] == 92)
            {
                return fileName.Replace('/', '\');
            }

            fileName = fileName.Replace('\', '/');
            if (HttpContext.Current != null)
            {
                return HttpContext.Current.Server.MapPath(fileName);
            }

            return (int)fileName[0] == 47 ? SitecoreLogFileAppender.MakePath(HttpRuntime.AppDomainAppPath, fileName.Replace('/', '\'), '\') : fileName;
        }
    }
}

请在此处查找更多信息:https://sitecore.unic.com/2015/01/27/create-a-single-sitecore-log-file-per-day

Sitecore 使用 log4net 作为其底层日志记录框架,这意味着您可以使用任何标准附加程序。尽管 Sitecore 添加了自定义 SitecoreLogFileAppender 附加程序,但您可以简单地使用 RollingFileAppender 并根据日期滚动日志文件。

您可以在文档的 log4net config examples section 中找到示例。

特别是对于 Sitecore,将附加程序更改为以下内容:

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender, Sitecore.Logging">
  <file value="$(dataFolder)/logs/log" />
  <appendToFile value="true" />
  <rollingStyle value="Date" />
  <maxSizeRollBackups value="30" />
  <datePattern value=".yyyyMMdd'.txt'" />
  <staticLogFileName value="false" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n" />
  </layout>
  <encoding value="utf-8" />
</appender>

关于上述配置变化的一些细节:

  • file :要登录的文件名。请注意,我们使用以下设置对其进行补充。
  • rollingStyle : 滚动每个文件的格式。
  • maxSizeRollBackups : 上面已经设置为30了,如果需要可以去掉这个节点。此值可确保 log4net 自动删除超过 30 天的任何日志。
  • datePattern :这设置滚动文件的日期格式。请注意,文件后缀包含在此处的单引号中。有关详细信息,请参阅此 previous answer
  • staticLogFileName :如果设置为 true,那么最新的日志文件将始终具有相同的名称,但请注意,由于您的 file 值没有文件后缀。

这些文件现在将以 log.yyyMMdd.txt 格式生成在与以前相同的日志文件夹中,并且不受每个应用程序生成不同文件的影响 restart/app 池回收。