最稳的pk10计划iphone 北京pk10计划手机软件 北京pk10数字的规律 超神手机版pk10软件 pk10北京赛车9码技巧 pk10四期倍投计划表 pk10极速赛车论坛 北京赛车冠军怎样选5码 北京赛车系统下载安装 pk10教程视频 北京pk10选号公式 北京赛车pk10赚钱技巧 北京赛车怎么提升概率 pk10技巧北京快三 北京pk10大小计划
VB.net 2010 視頻教程 VB.net 2010 視頻教程 python基礎視頻教程
SQL Server 2008 視頻教程 c#入門經典教程 Visual Basic從門到精通視頻教程
當前位置:
首頁 > 編程開發 > c#教程 >
  • C#教程之[開源]基于Log4Net簡單實現KafkaAppender

  • 2019-04-13 19:26 來源:未知

背景#

  1. 基于之前基于Log4Net本地日志服務簡單實現 實現本地日志服務,但是隨著項目開發演進,本地日志服務滿足不了需求,譬如在預發布環境或者生產環境,不可能讓開發人員登錄查看本地日志文件分析。
  2. Kafka+ELK日志服務套件,可以在線日志服務可以解決上述問題,并且提供豐富報表分析等等;
  3. 具體源碼:MasterChief
  4. Nuget:Install-Package MasterChief.DotNet.Core.KafkaLog
  5. 歡迎Star,歡迎Issues;

源碼#

  1. 基于Log4Net來實現與kafka通訊Appender

    
    			
    Copy
    public class KafkaAppender : AppenderSkeleton { #region Fields /// <summary> /// Kafka 生產者 /// </summary> private Producer _kafkaProducer; #endregion Fields #region Properties /// <summary> /// Brokers /// </summary> public string Brokers { get; set; } /// <summary> /// Topic /// </summary> public string Topic { get; set; } #endregion Properties #region Methods /// <summary> /// Initialize the appender based on the options set /// </summary> /// <remarks> /// <para> /// This is part of the <see cref="T:log4net.Core.IOptionHandler" /> delayed object /// activation scheme. The <see cref="M:log4net.Appender.AppenderSkeleton.ActivateOptions" /> method must /// be called on this object after the configuration properties have /// been set. Until <see cref="M:log4net.Appender.AppenderSkeleton.ActivateOptions" /> is called this /// object is in an undefined state and must not be used. /// </para> /// <para> /// If any of the configuration properties are modified then /// <see cref="M:log4net.Appender.AppenderSkeleton.ActivateOptions" /> must be called again. /// </para> /// </remarks> public override void ActivateOptions() { base.ActivateOptions(); InitKafkaProducer(); } /// <summary> /// Subclasses of <see cref="T:log4net.Appender.AppenderSkeleton" /> should implement this method /// to perform actual logging. /// </summary> /// <param name="loggingEvent">The event to append.</param> /// <remarks> /// <para> /// A subclass must implement this method to perform /// logging of the <paramref name="loggingEvent" />. /// </para> /// <para> /// This method will be called by <see cref="M:DoAppend(LoggingEvent)" /> /// if all the conditions listed for that method are met. /// </para> /// <para> /// To restrict the logging of events in the appender /// override the <see cref="M:PreAppendCheck()" /> method. /// </para> /// </remarks> protected override void Append(LoggingEvent loggingEvent) { try { var message = GetLogMessage(loggingEvent); var topic = GetTopic(loggingEvent); _ = _kafkaProducer.SendMessageAsync(topic, new[] {new Message(message)}); } catch (Exception ex) { ErrorHandler.Error("KafkaProducer SendMessageAsync", ex); } } /// <summary> /// Raises the Close event. /// </summary> /// <remarks> /// <para> /// Releases any resources allocated within the appender such as file handles, /// network connections, etc. /// </para> /// <para> /// It is a programming error to append to a closed appender. /// </para> /// </remarks> protected override void OnClose() { base.OnClose(); StopKafkaProducer(); } private string GetLogMessage(LoggingEvent loggingEvent) { var builder = new StringBuilder(); using (var writer = new StringWriter(builder)) { Layout.Format(writer, loggingEvent); if (Layout.IgnoresException && loggingEvent.ExceptionObject != null) writer.Write(loggingEvent.GetExceptionString()); return writer.ToString(); } } private string GetTopic(LoggingEvent loggingEvent) { return string.IsNullOrEmpty(Topic) ? Path.GetFileNameWithoutExtension(loggingEvent.Domain) : Topic; } /// <summary> /// 初始化Kafka 生產者 /// </summary> private void InitKafkaProducer() { try { if (string.IsNullOrEmpty(Brokers)) Brokers = "http://localhost:9200"; if (_kafkaProducer == null) { var brokers = new Uri(Brokers); var kafkaOptions = new KafkaOptions(brokers) { Log = new KafkaLog() }; _kafkaProducer = new Producer(new BrokerRouter(kafkaOptions)); } } catch (Exception ex) { ErrorHandler.Error("InitKafkaProducer", ex); } } /// <summary> /// 停止生產者 /// </summary> private void StopKafkaProducer() { try { _kafkaProducer?.Stop(); } catch (Exception ex) { ErrorHandler.Error("StopKafkaProducer", ex); } } #endregion Methods }
  2. 基于之前定義接口,來實現kafkaLogService

    
    			
    Copy
    public sealed class KafkaLogService : ILogService { #region Constructors /// <summary> /// Initializes the <see cref="FileLogService" /> class. /// </summary> static KafkaLogService() { KafkaLogger = LogManager.GetLogger(KafkaLoggerName); } #endregion Constructors #region Fields /// <summary> /// Kafka logger name /// </summary> public const string KafkaLoggerName = "KafkaLogger"; /// <summary> /// Kafka logger /// </summary> public static readonly ILog KafkaLogger; #endregion Fields #region Methods /// <summary> /// Debug記錄 /// </summary> /// <param name="message">日志信息</param> public void Debug(string message) { if (KafkaLogger.IsDebugEnabled) KafkaLogger.Debug(message); } /// <summary> /// Debug記錄 /// </summary> /// <param name="message">日志信息</param> /// <param name="ex">異常信息</param> public void Debug(string message, Exception ex) { if (KafkaLogger.IsDebugEnabled) KafkaLogger.Debug(message, ex); } /// <summary> /// Error記錄 /// </summary> /// <param name="message">日志信息</param> public void Error(string message) { if (KafkaLogger.IsErrorEnabled) KafkaLogger.Error(message); } /// <summary> /// Error記錄 /// </summary> /// <param name="message">日志信息</param> /// <param name="ex">異常信息</param> public void Error(string message, Exception ex) { if (KafkaLogger.IsErrorEnabled) KafkaLogger.Error(message, ex); } /// <summary> /// Fatal記錄 /// </summary> /// <param name="message">日志信息</param> public void Fatal(string message) { if (KafkaLogger.IsFatalEnabled) KafkaLogger.Fatal(message); } /// <summary> /// Fatal記錄 /// </summary> /// <param name="message">日志信息</param> /// <param name="ex">異常信息</param> public void Fatal(string message, Exception ex) { if (KafkaLogger.IsFatalEnabled) KafkaLogger.Fatal(message, ex); } /// <summary> /// Info記錄 /// </summary> /// <param name="message">日志信息</param> public void Info(string message) { if (KafkaLogger.IsInfoEnabled) KafkaLogger.Info(message); } /// <summary> /// Info記錄 /// </summary> /// <param name="message">日志信息</param> /// <param name="ex">異常信息</param> public void Info(string message, Exception ex) { if (KafkaLogger.IsInfoEnabled) KafkaLogger.Info(message, ex); } /// <summary> /// Warn記錄 /// </summary> /// <param name="message">日志信息</param> public void Warn(string message) { if (KafkaLogger.IsWarnEnabled) KafkaLogger.Warn(message); } /// <summary> /// Warn記錄 /// </summary> /// <param name="message">日志信息</param> /// <param name="ex">異常信息</param> public void Warn(string message, Exception ex) { if (KafkaLogger.IsWarnEnabled) KafkaLogger.Warn(message, ex); } #endregion Methods }
  3. 修改Log4Net.Config,定義Kafka的Topic以及Brokers

    
    			
    Copy
    <appender name="KafkaAppender" type="MasterChief.DotNet.Core.KafkaLog.KafkaAppender, MasterChief.DotNet.Core.KafkaLog"> <param name="Topic" value="beats" /> <param name="Brokers" value="http://localhost:9092" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="發生時間:%date %newline事件級別:%-5level %newline事件來源:%logger%newline日志內容:%message%newline" /> </layout> </appender>

使用#

  1. 由于基于上篇說的日志接口,所以可以通過Ioc切換,而且不影響在業務代碼調用;
  2. 基于業務需求,您可以同時落地本地日志,保證網絡抖動或者不正常的時候能夠正常記錄日志;

結語#

  1. 小弟不才,大佬輕拍;

作者:YanZhiwei

出處:https://www.cnblogs.com/MeetYan/p/10693545.html

本站使用「署名 4.0 國際」創作共享協議,轉載請在文章明顯位置注明作者及出處。


pk10赛车冠军技巧
最稳的pk10计划iphone 北京pk10计划手机软件 北京pk10数字的规律 超神手机版pk10软件 pk10北京赛车9码技巧 pk10四期倍投计划表 pk10极速赛车论坛 北京赛车冠军怎样选5码 北京赛车系统下载安装 pk10教程视频 北京pk10选号公式 北京赛车pk10赚钱技巧 北京赛车怎么提升概率 pk10技巧北京快三 北京pk10大小计划
贵州11选5大奖 浙江快乐彩票12选五 血拼斗地主支持三人癞子比赛玩法 燕赵风采20选5开奖结果 大乐透走势图带连线图 黑龙江22选5奖池多少 抖音的赚钱规则 lg游戏注册送20 澳洲幸运10的高手精准计划