Redis-RedisとLog 4 Netは分散ログ記録を完成した




一、考え方


私たちのプログラムの様々な異常を単独で記録するために、私たちはこのようにします:1つのキューを作成して、異常が発生した時、異常をキューに入れて、また、私たちはプログラムが起動する時、1つのスレッドを開いて、異常を格納したキューから異常情報を取得して、ファイルを書き込むために使用します.
シミュレーションコード:
カスタム例外が発生したときの処理クラス:
                      
 public class MyExceptionAttribute:System.Web.Mvc.HandleErrorAttribute
    {
        //       
        public static Queue<Exception> exceptionQueue = new Queue<Exception>();

        /*      */
        public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
        {

            exceptionQueue.Enqueue(filterContext.Exception); //       
            filterContext.HttpContext.Response.Redirect("/error.html");//      
            base.OnException(filterContext);
        }
    }

filterConfigのメソッドを変更します(例外が発生した場合、カスタムクラスに例外を渡して処理します):
 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
           // filters.Add(new HandleErrorAttribute());
            filters.Add(new MyExceptionAttribute());
        }

        
アプリケーションのエントリ方法を変更するには、次の手順に従います.
        
 protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //           ,             
            String logPath = Server.MapPath("/Log/");
            ThreadPool.QueueUserWorkItem(o => {
                while (true)
                {
                    try
                    {
                        if (MyExceptionAttribute.exceptionQueue.Count > 0)
                        {
                            Exception e=MyExceptionAttribute.exceptionQueue.Dequeue();//        
                            if (e != null)
                            {
                                //         
                                String fileName = logPath + DateTime.Now.ToString("yyyy-MM-dd")+".txt";

                                string errorMsg = e.ToString();
                                File.AppendAllText(fileName,errorMsg,Encoding.Default);//      


                            }
                            else
                            {
                                Thread.Sleep(30);
                            }
                        }
                        else
                        {
                            Thread.Sleep(30);//  cpu  
                        }
                    }
                    catch(Exception e)
                    {
                        MyExceptionAttribute.exceptionQueue.Enqueue(e);
                    }
                   

                   
                }
            }, logPath);
        }
    }

二、redisを用いて異常情報キューを作り、log 4 netを用いてログ処理を行う


大規模なWebサイトでは、アプリケーションサーバから例外情報キューを分離し、ここではredisを使用して例外情報を格納しますが、例外情報が発生した後、log 4 net処理に例外情報を渡します.
     
キューの変更:
 public class MyExceptionAttribute:System.Web.Mvc.HandleErrorAttribute
    {
        //       
       // public static Queue<Exception> exceptionQueue = new Queue<Exception>();
        public static IRedisClientsManager clientManager = new PooledRedisClientManager(new String[]{"127.0.0.1:6379"});

        public static IRedisClient reidsClient = clientManager.GetClient();

        /*      */
        public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
        {

            //exceptionQueue.Enqueue(filterContext.Exception); //       

            reidsClient.EnqueueItemOnList("exception", filterContext.Exception.ToString());//        redis   
            filterContext.HttpContext.Response.Redirect("/error.html");//      
            base.OnException(filterContext);
        }
    }

   
log 4 netでエラー情報を処理するように変更します.
      
 protected void Application_Start()
        {
            log4net.Config.XmlConfigurator.Configure();//  log4net    (     web.config )

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //           ,             
            String logPath = Server.MapPath("/Log/");
            ThreadPool.QueueUserWorkItem(o => {
                while (true)
                {
                    try
                    {
                       // if (MyExceptionAttribute.exceptionQueue.Count > 0)
                        if (MyExceptionAttribute.reidsClient.GetListCount("exception") > 0)
                        {
                            //Exception e=MyExceptionAttribute.exceptionQueue.Dequeue();//        
                            String errorMsg = MyExceptionAttribute.reidsClient.DequeueItemFromList("exception"); // redis         
                            if (errorMsg != null)
                            {
                                //         
                               // String fileName = logPath + DateTime.Now.ToString("yyyy-MM-dd")+".txt";

                               // string errorMsg = e.ToString();
                              //  File.AppendAllText(fileName, errorMsg, Encoding.Default);//      

                                /*  log4net        */
                                ILog logger = LogManager.GetLogger("appError");
                                logger.Error(errorMsg);//       log4net 



                            }
                            else
                            {
                                Thread.Sleep(30);
                            }
                        }
                        else
                        {
                            Thread.Sleep(30);//  cpu  
                        }
                    }
                    catch(Exception e)
                    {
                        MyExceptionAttribute.reidsClient.EnqueueItemOnList("exception", e.ToString());//        redis   
                    }
                   

                   
                }
            }, logPath);
        }
    }

ps:log 4 netプロファイル:
 <log4net>
    <!-- OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
    <!-- Set root logger level to ERROR and its appenders -->
    <root>
      <level value="ALL"/>
      <appender-ref ref="SysAppender"/>
    </root>
    <!-- Print only messages of level DEBUG or above in the packages -->
    <logger name="WebLogger">
      <level value="DEBUG"/>
    </logger>
    <appender name="SysAppender"
type="log4net.Appender.RollingFileAppender,log4net" >
      <param name="File" value="App_Data/" />
      <param name="AppendToFile" value="true" />
      <param name="RollingStyle" value="Date" />
      <param name="DatePattern" value=""Logs_"yyyyMMdd".txt"" />
      <param name="StaticLogFileName" value="false" />
      <layout type="log4net.Layout.PatternLayout,log4net">
        <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
        <param name="Header" value="
----------------------header--------------------------
" />
        <param name="Footer" value="
----------------------footer--------------------------
" />
      </layout>
    </appender>
    <appender name="consoleApp" type="log4net.Appender.ConsoleAppender,log4net">
      <layout type="log4net.Layout.PatternLayout,log4net">
        <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
      </layout>
    </appender>
  </log4net>

ノード構成の処理:
 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
      <!--Log4Net  -->

ウェブサイトの正常な使用では、私たちのredisサーバは一般的に私たちのアプリケーションサーバと分離されています.これにより、私たちのキューはアプリケーションサーバのリソースを占有せず、さらに拡張され、私たちのログもアプリケーションサーバから単独で剥離され、サービス専用になります.