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サーバは一般的に私たちのアプリケーションサーバと分離されています.これにより、私たちのキューはアプリケーションサーバのリソースを占有せず、さらに拡張され、私たちのログもアプリケーションサーバから単独で剥離され、サービス専用になります.
私たちのプログラムの様々な異常を単独で記録するために、私たちはこのようにします: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サーバは一般的に私たちのアプリケーションサーバと分離されています.これにより、私たちのキューはアプリケーションサーバのリソースを占有せず、さらに拡張され、私たちのログもアプリケーションサーバから単独で剥離され、サービス専用になります.
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);
}
}
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);
}
}
<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 -->