搭建一套自己实用的.net架构(2)【日志模块-log4net】

先谈谈简单的模块,日志。在系统中日志模块是必须的,什么系统日志,操作日志,调试日志。这里用的是log4net

对log4net还不熟悉的小伙伴们赶快去搜索基础教程哦, 我这里就不温故了。

那么有人要问了,log4net确实很强大,而且我们也会用。还要单独写一篇文章来介绍,有必要吗?

我简单的举两个场景:

1:log4net写入DB 还需要在 log4net中配置数据库连接字符串,   我想log4net 和 我的 connectionStrings 用1个配置不行吗?

2:log4net写入参数扩展问题,我配置文件想写入ip地址,那我代码还要定义一个ip的参数。 那我再扩展,还需要再定义,这改动量太大了,能不能只传一个实体类,让log4net自己去映射那?这样我就可以写一些通用的方法,好多项目都可以直接拿过来用,代码修改量也少了点。

有人觉得这都不是问题,高手请跳过。

我这里将日志模块单独封装了一个HY.Log,截图如下:

看图有点乱,下面我给大家捋一捋(念lv  念成lu的去面壁思过  ):

第一步:实现自定义参数

我们要在PatternConverter文件夹中定义一些可扩展参数,这样就可以在log4net配置文件中随心使用了,哪截图中我实现了获取客户端ip、获取服务器端ip

或许服务器mac地址。

就拿ClientIpPatternConverter.cs来说需要继承log4net下  log4net.Layout.Pattern.PatternLayoutConverter类,来实现扩展。

using System.IO;
using log4net.Core;
using log4net.Layout.Pattern;

namespace HY.Log.PatternConverter
{
    /// <summary>
    /// B/S 客户端地址扩展
    /// </summary>
    internal class ClientIpPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            writer.Write(HY.Utilities.IPHelper.GetRemoteIPAddress());
        }
    }
}

接着在分别实现 MAC、服务端IP、 以及其它你任何想扩展的参数。

ObjectPatternConverter.cs 这个类就比较特殊了。这个自定义参数其实是让你传入一个实体类,然后通过反射技术,让log4net通过配置文件的 配置自动映射要传入的值。

上面的类 是针对特定的通用功能扩展,这个类只需要定义一个即可。

using System.IO;
using System.Reflection;
using log4net.Core;
using log4net.Layout.Pattern;

namespace HY.Log.PatternConverter
{
    internal class ObjectPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            if (Option != null)
            {
                // Write the value for the specified key
                WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
            }
            else
            {
                // Write all the key value pairs
                WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
            }
        }

        /// <summary>
        /// 通过反射获取传入的日志对象的某个属性的值
        /// </summary>
        /// <param name="property"></param>
        /// <param name="loggingEvent"></param>
        /// <returns></returns>
        private object LookupProperty(string property, LoggingEvent loggingEvent)
        {
            object propertyValue = string.Empty;
            PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);
            if (propertyInfo != null)
                propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);
            return propertyValue;
        }
    }
}

第二步:实现log4net自定义布局,将自定义参数进行注册

 CustomLayout.cs

using HY.Log.PatternConverter;
using log4net.Layout;

namespace HY.Log
{
    /// <summary>
    /// 定义log日志布局的参数信息
    /// </summary>
    public class CustomLayout : PatternLayout
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public CustomLayout()
        {
            #region 内部自定义
            AddConverter("ServerIP", typeof(ServerIpPatternConverter));
            AddConverter("ClientIP", typeof(ClientIpPatternConverter));
            AddConverter("MAC", typeof(MacPatternConverter));
            #endregion

            #region 支持开发人员自定义
            AddConverter("Object", typeof(ObjectPatternConverter));
            #endregion
        }
    }
}

代码将自定义的参数以 key value 的形式进行注册, 以后我们再log4net进行配置的时候 就要记住这些关键字了, 这都是你自己定义的。

你敢在代码中实现  AddConverter("XXOO", typeof(XXOOPatternConverter));  吗?

第三步:定义自己框架的Log接口并实现它

没啥可说的,看代码吧。

LogMessage.cs   这个类其实就是写了一个传入的的自定义参数的实体类,你可以自己写。不过最好是继承这个类进行扩展。

using System;

namespace HY.Log
{
    /// <summary>
    /// 用于记录日志信息
    /// </summary>
    [Serializable]
    public class LogMessage
    {
        /// <summary>
        /// 日志信息
        /// </summary>
        public string Message { get; set; }

    }
}

ILog.cs

using System;

namespace HY.Log
{
    public interface ILog
    {
        /// <summary>
        /// 写入Debug日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        void Debug(string message, Exception exception = null);

        /// <summary>
        /// 写入Debug日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        void Debug(object messageEntity, Exception exception = null);

        /// <summary>
        /// 写入Info日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        void Info(string message, Exception exception = null);

        /// <summary>
        /// 写入Info日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        void Info(object messageEntity, Exception exception = null);

        /// <summary>
        /// 写入Warn日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        void Warn(string message, Exception exception = null);

        /// <summary>
        /// 写入Warn日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        void Warn(object messageEntity, Exception exception = null);

        /// <summary>
        /// 写入Error日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        void Error(string message, Exception exception = null);

        /// <summary>
        /// 写入Error日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        void Error(object messageEntity, Exception exception = null);

        /// <summary>
        /// 写入Fatal日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        void Fatal(string message, Exception exception = null);

        /// <summary>
        /// 写入Fatal日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        void Fatal(object messageEntity, Exception exception = null);

    }
}

NormalLog.cs

using System;
using System.Collections.Generic;

namespace HY.Log
{
    public class NormalLog : ILog
    {
        #region private
        private static Dictionary<string, log4net.ILog> listILog = new Dictionary<string, log4net.ILog>();   //Log对象集合
        private log4net.ILog iLog;  //当前日志对象的实例
        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数,传入Log4NET 的ILog对象
        /// </summary>
        /// <param name="logger"></param>
        public NormalLog(log4net.ILog logger)
        {
            string LoggerName = logger.Logger.Name;     //logger 配置节名称
            if (!listILog.ContainsKey(LoggerName))
            {
                lock (listILog)
                {
                    if (!listILog.ContainsKey(LoggerName))
                    {
                        listILog.Add(LoggerName, logger);
                    }
                    else
                    {
                        listILog[LoggerName] = logger;
                    }
                }
            }
            else if (listILog[LoggerName] == null)
            {
                listILog[LoggerName] = logger;
            }
            iLog = listILog[LoggerName];
        }

        public NormalLog(string loggerName)
        {
            log4net.ILog logger = log4net.LogManager.GetLogger(loggerName);
            string LoggerName = logger.Logger.Name;     //logger 配置节名称
            if (!listILog.ContainsKey(LoggerName))
            {
                listILog.Add(LoggerName, logger);
            }
            else if (listILog[LoggerName] == null)
            {
                listILog[LoggerName] = logger;
            }
            iLog = listILog[LoggerName];
        }

        #endregion

        #region 写入日志

        /// <summary>
        /// 写入Debug日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        public void Debug(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Debug(messageEntity, exception);
        }

        /// <summary>
        /// 写入Debug日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        public void Debug(object messageEntity, Exception exception = null)
        {
            if (iLog.IsDebugEnabled)
            {
                if (exception != null)
                {
                    iLog.Debug(messageEntity, exception);
                }
                else
                {
                    iLog.Debug(messageEntity);
                }
            }
        }

        /// <summary>
        /// 写入Info日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        public void Info(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Info(messageEntity, exception);
        }

        /// <summary>
        /// 写入Info日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        public void Info(object messageEntity, Exception exception = null)
        {
            if (iLog.IsInfoEnabled)
            {
                if (exception != null)
                {
                    iLog.Info(messageEntity, exception);
                }
                else
                {
                    iLog.Info(messageEntity);
                }
            }
        }

        /// <summary>
        /// 写入Warn日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        public void Warn(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Warn(messageEntity, exception);
        }

        /// <summary>
        /// 写入Warn日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        public void Warn(object messageEntity, Exception exception = null)
        {
            if (iLog.IsWarnEnabled)
            {
                if (exception != null)
                {
                    iLog.Warn(messageEntity, exception);
                }
                else
                {
                    iLog.Warn(messageEntity);
                }
            }
        }

        /// <summary>
        /// 写入Error日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        public void Error(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Error(messageEntity, exception);
        }

        /// <summary>
        /// 写入Error日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        public void Error(object messageEntity, Exception exception = null)
        {
            if (iLog.IsErrorEnabled)
            {
                if (exception != null)
                {
                    iLog.Error(messageEntity, exception);
                }
                else
                {
                    iLog.Error(messageEntity);
                }
            }
        }

        /// <summary>
        /// 写入Fatal日志,
        /// </summary>
        /// <param name="message">日志信息,占位符为 %Object{Message}</param>
        public void Fatal(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Fatal(messageEntity, exception);
        }

        /// <summary>
        /// 写入Fatal日志
        /// </summary>
        /// <param name="messageEntity">日志实体信息, 占位符为 %Object{实体类的属性名称}</param>
        public void Fatal(object messageEntity, Exception exception = null)
        {
            if (iLog.IsFatalEnabled)
            {
                if (exception != null)
                {
                    iLog.Fatal(messageEntity, exception);
                }
                else
                {
                    iLog.Fatal(messageEntity);
                }
            }
        }
        #endregion

    }
}

第四步:写一下log模块的支持方法(这里有实现log4net配置和连接字符串共用一个配置的方法)

LogManager.cs

这个类定义的了log4net模块的初始化,数据库连接设置……

using System;
using System.IO;
using log4net.Appender;
using log4net.Config;
using log4net.Repository.Hierarchy;

namespace HY.Log
{
    public class LogManager
    {

        /// <summary>
        /// 设置DB连接字符串
        /// </summary>
        /// <param name="conString">连接字符串</param>
        /// <param name="loggerName">loggerName</param>
        /// <param name="appenderName">appenderName</param>
        public static void ConfigConnection(string conString, string loggerName, string appenderName = "ADONetAppender")
        {
            try
            {
                Hierarchy h = log4net.LogManager.GetRepository() as Hierarchy;
                if (h != null)
                {
                    AdoNetAppender adoAppender = (AdoNetAppender)h.GetLogger(loggerName,
                        h.LoggerFactory).GetAppender(appenderName);
                    if (adoAppender != null)
                    {
                        adoAppender.ConnectionString = conString;
                        adoAppender.ActivateOptions();
                    }
                }

            }
            catch (NullReferenceException) { }
        }

        /// <summary>
        /// 初始化HY.Log,  Log配置文件需要写到 Web.config  OR  App.config
        /// </summary>
        public static void Init()
        {
            XmlConfigurator.Configure();
        }

        /// <summary>
        /// 初始化HY.Log,
        /// </summary>
        /// <param name="configFileName">制定Log配置文件的文件绝对路径</param>
        public static void Init(string configFileName)
        {
            XmlConfigurator.Configure(new FileInfo(configFileName));
        }

        /// <summary>
        /// 检索Logger名称返回日志处理接口
        /// </summary>
        /// <param name="name">Logger名称</param>
        /// <returns>日志接口</returns>
        public static ILog GetLogger(string name)
        {
            var log4Logger = log4net.LogManager.GetLogger(name);
            return new NormalLog(log4Logger);
        }

    }
}

第五步:如何使用HY.Log.DLL

上面的代码大家看到了,已经可以成功编译一个dll 文件了。

先来编辑一个log4net配置文件

<?xml version="1.0"?>
<configuration>
  <!--Log4net Begin-->
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <!--Log4net Begin,程序运行异常记录-->

    <logger name="LogInfoDB">
      <level value="ALL" />
      <appender-ref ref="ADONetAppender" />
    </logger>
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
      <bufferSize value="1" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <!--<connectionString value="Data Source=127.0.0.1;Database=test;uid=sa;pwd=test;Max Pool Size=300;Connect Timeout=15;" />-->
      <commandText value="INSERT INTO HY_Log ([LogType],[ModelName],[Message],[Exception],[IP],[Log_Date],[UserID]) VALUES (@LogType,@ModelName, @Message, @Exception, @IP,@Log_Date,@UserID)" />
      <parameter>
        <parameterName value="@LogType" />
        <dbType value="String" />
        <size value="20" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{LogType}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@ModelName" />
        <dbType value="String" />
        <size value="110" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{ModelName}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Message" />
        <dbType value="String" />
        <size value="2000" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{Message}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Exception" />
        <dbType value="String" />
        <size value="8000" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{Exception}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@IP" />
        <dbType value="String" />
        <size value="20" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%ClientIP" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Log_Date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@UserID" />
        <dbType value="String" />
        <size value="100" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{UserID}" />
        </layout>
      </parameter>
    </appender>

  </log4net>
  <!--Log4net End-->
</configuration>

<!--%m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息
      %n(new line):换行
      %d(datetime):输出当前语句运行的时刻
      %r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数
      %t(thread id):当前语句所在的线程ID
      %p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等
      %c(class):当前日志对象的名称,例如:
      %f(file):输出语句所在的文件名。
      %l(line):输出语句所在的行号。-->

上面的配置文件是一个写入DB的配置

请注意如下配置节:

<layout type="HY.Log.CustomLayout"><conversionPattern value="%Object{Exception}" /><conversionPattern value="%Object{LogType}" /><conversionPattern value="%ClientIP" />这便是采用了自定义配置。

创建HY.ILog对象public static ILog ilog = null;

HY.Log.LogManager.Init(HttpContext.Current.Server.MapPath(@"~/Config/log4net.config"));//加载配置文件HY.Log.LogManager.ConfigConnection(ConfigurationManager.ConnectionStrings["Connection"].ToString(), "LogInfoDB");//修改连接字符串ilog = LogManager.GetLogger("LogInfoText");     //获取Ilog对象    这里可以采用单例模式。代码就不贴了, 

自定义实体类:
 [Serializable]
    public class LogEntity
    {
        /// <summary>
        /// 日志类型
        /// </summary>
        public LogType LogType { get; set; }

        /// <summary>
        /// 模块名称
        /// </summary>
        public string ModelName { get; set; }

        /// <summary>
        /// 信息
        /// </summary>
        public new string Message { get; set; }

        /// <summary>
        /// 异常信息
        /// </summary>
        public string Exception { get; set; }

        public string UserID { get; set; }
 LogEntity loginfo = new LogEntity();           loginfo.ModelName = "ModelName";           loginfo.Message = "Message";           loginfo.Exception = "Exception";           loginfo.UserID = "UserID";           loginfo.LogType = "LogType.Business";ilog.Error(loginfo,ex); 
 
 到这里就已经完了。  关于使用的代码比较粗糙,这块就需要根据你程序的具体需求来实现了。这里点到为止。  因为后续我们将会采用spring.net来注入。 将在后续的文章介绍。

各位如果有更好的建立请给我留言, 请各位不吝赐教。 

相关文章:

搭建一套自己实用的.net架构(1)【概述】

搭建一套自己实用的.net架构(2)【日志模块-log4net】

时间: 2024-10-12 19:21:38

搭建一套自己实用的.net架构(2)【日志模块-log4net】的相关文章

搭建一套自己实用的.net架构(3)续 【ORM Dapper+DapperExtensions+Lambda】

前言 继之前发的帖子[ORM-Dapper+DapperExtensions],对Dapper的扩展代码也进行了改进,同时加入Dapper 对Lambda表达式的支持. 由于之前缺乏对Lambda的知识,还是使用了拿来主义.研究了些案例,总归有些问题: 1.只能生成sql.不能将值进行参数化. 2.lambda解析的代码对sql语法的多样式支持不够 3.不开源,反编译后发现可扩展性不强. 最后选择了Dos.ORM(lambda支持的很好,开源的),在这里尊重原创,大家有兴趣去支持下哈. [作者博

搭建一套自己实用的.net架构(4)【CodeBuilder-RazorEngine】

工欲善其事必先利其器,  下面来说说代码生成器. 现在代码生成器品种繁多各式各样, 什么codesmith.T4. 动软也算.那么每款代码生成器都有自己模板解析引擎. 现在比较流行的 NVelocity(之前我用这个,不过在实际过程中遇到了很多关键字冲突的问题.不单单是$), 最后只好改成了RazorEngine. Razorengine源码: http://razorengine.codeplex.com/ 如果你在mvc项目中,原项目和mvc的Antlr3.Runtime.dll版本有冲突,

搭建一套自己实用的.net架构(3)【ORM-Dapper+DapperExtensions】

现在成熟的ORM比比皆是,这里只介绍Dapper的使用(最起码我在使用它,已经运用到项目中,小伙伴们反馈还可以). 优点: 1.开源.轻量.小巧.上手容易. 2.支持的数据库还蛮多的, Mysql,SqlLite,Sqlserver,Oracle等一系列的数据库. 3.Dapper原理通过Emit反射IDataReader的序列队列来快速的得到和产生对象.性能貌似很牛逼的样子 缺点: 作为一款ORM太过于轻量级了,根据对象自动生成sql的功能还是空白,需要自己来扩展, 当然这也是优点,  好声音

搭建一套自己实用的.net架构 一

入园很久,一直默默的潜水,近来得空想写点什么. 思前想后,那就把自己平时没事干自己摘抄.引用.瞎写的一些东西写出来.帮助自己巩固一下,顺便请高手们指点一二. 我本人很懒 ,一些代码就是直接复制别人的劳动成果,或者加之改动,拼凑起的一些东西.  这些无所谓了 ,能实现最终目的让程序跑起来再说.如果某些代码或者言论侵犯了您的权益,请通知我删除掉. 本文写作目的是为了学习交流……  谢谢. 蛋逼了半天,下面开始说正事.先把解决方案截图贴出来,大家应该一看便知. 如上截图, 框架方面实现了, 缓存.日志

【干货】手动搭建一套可自动化构建的微服务框架

如何阅读 本文篇幅较长,我花了两天的时间完成,大约需要半小时阅读. 本文分为理论篇和实践篇,由于代码在手机端展示并不理想,建议大家收藏之后在PC端阅读.实践篇边动手边阅读更有助于理解. 在阅读的同时,也麻烦各位大佬多多分享! 本文你将学到什么? 本文将以原理+实战的方式,首先对"微服务"相关的概念进行知识点扫盲,然后开始手把手教你搭建这一整套的微服务系统. 这套微服务框架能干啥? 这套系统搭建完之后,那可就厉害了: 微服务架构你的整个应用程序将会被拆分成一个个功能独立的子系统,独立运行

从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社

从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社 PPT链接: https://pan.baidu.com/s/1i5Jrr1N 视频链接: https://v.qq.com/x/page/n0386utnrb0.html?start=492

用iptables搭建一套强大的安全防护盾

iptables功能: 搭建一套防火墙规则 进行攻击防护.访问策略 进行数据包转发 Netfilter: Linux系统核心层内部的一个数据包处理模块 Hook point:(PRE_ROUTING.INPUT.OUTPUT.FORWARD.POST_ROUTING) 数据包在Netfilter中的挂载点 iptables规则组成: 四张表 + 五条链(Hook point) + 规则 四张表:filter表.nat表.mangle表.raw表 filter表:访问控制.规则匹配 nat表:地址

如何管理团队知识?快速搭建一套管理工具

阅读全文需要15分钟,动手实践需要30分钟,请收藏点赞后再读. 演示地址:http://birddoc.jayh.club Github链接:https://github.com/Jackson0714/BirdDoc   记得点个Star 一.用互联网思维来看知识管理工具 1.1 用户故事 我是一名开发人员,经常会迷失在寻找团队内的各种开发文档中,我期望有一个网站,所有文档都集中在这个网站中,我可以进行根据目录浏览,最好能支持搜索,而且我贡献的文档别人不知道,会再跑过来问我. 1.2 用户痛点

varnish的架构和日志

varnish的架构和日志 varnish的架构 知道varnish的内部结构有两个重要的原因: 首先,架构主要负责性能,其次,它影响你如何将Varnish集成到你自己的架构中. 主程序块是Manager进程,包含在二进制程序varnishd中. Manager进程的任务是将任务包括缓存委托给子进程. Manager进程确保每个任务总是有一个进程. 这样设计的主要驱动因素就是安全性. 可以通过以下方式访问Manager的命令行界面(CLI): 1)varnishadm管理界面部分, 2)Varn