طريقة منفصلة تسجيل في جافا / logback

بارت كتابة بعض السجلات


مهمة


دعنا نقول أننا أردنا تسجيل كل طريقة لفئة Java معينة بطريقة مختلفة:


  • كل طريقة لها ملف السجل الخاص بها ،
  • ... تنسيق السجل الخاص بك ،
  • ... الحد الأدنى لمستوى التسجيل ،
  • نقوم بتوسيع تنسيق السجل باستخدام % الخاصة بنا ،
  • القدرة على تحديث هذا التكوين على الطاير.

يوضح هذا المقال كيفية تلبية هذه المتطلبات. من أجل الحفاظ على البساطة ، لا يتم الفصل بين التسجيل إلا بالطرق ؛ في الواقع ، قد ترغب في الحصول على تهيئة مؤهلة للتسلسل الهرمي ، مثل ... سيكون الرابط إلى الكود المصدري الكامل أدناه.


كود العميل


  class ThingService { log = LoggerFactory.getLogger(); getThing() { log.debug("getThing..."); // => one.log } listThings() { log.debug("listThings..."); // => another.log } } 

Logback


للتنفيذ ، تم تحديد مكتبة تسجيل "logback" صلبة ، والتي توفر إمكانيات مثيرة للتخصيص:


 ch.qos.logback:logback-classic:1.2.3 

تم تكوينه من كلٍ من تهيئة XML ومباشرة من Java ، يمكن دمج الأساليب:


  public void configureLogback() throws JoranException { LoggerContext lc = LoggerFactory.getILoggerFactory(); lc.reset(); // reset prev config JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(lc); configurator.doConfigure("config.xml"); // any data source StatusPrinter.printInCaseOfErrorsOrWarnings(lc); //   : Logger root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); root.setLevel(Level.INFO); //  } 

باختصار حول التسجيل:


  1. مبرمج يسحب المسجل ،
  2. المسجل يسحب الملحقة المعينة له ،
  3. يفكر الملتزم ويدعو المشفر ،
  4. يقوم المشفر بتنسيق سطر واحد تمامًا من السجل ،
  5. للقيام بذلك ، يقوم بسحب سلسلة من المحولات ، كل منها يكشف عن % ،
  6. النجاح.

للبساطة ، تم اختيار تكوين جافا خالص. كل شيء واضح هنا إذا كنت تضع في الاعتبار تهيئة XML. تتمثل المهمة الرئيسية في إنشاء مرشد / مُشفّر خاص بك وتسجيله - سيتم استدعاءهم بواسطة logback من أحشاءهم. يجب تذكر كل كائن تقريبًا للبدء في استخدام طريقة start() . مثال مجردة:


  Logger rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); LoggerContext lc = rootLogger.getLoggerContext(); lc.reset(); // reset prev config var encoder = new PatternLayoutEncoder(); encoder.setContext(lc); encoder.setPattern("%-5level %message%n"); encoder.start(); var appender = new ConsoleAppender<ILoggingEvent>(); appender.setContext(lc); appender.setEncoder(encoder); appender.start(); rootLogger.setLevel(Level.DEBUG); rootLogger.addAppender(appender); 

افصل الطرق المسجلة عن بعضها البعض


بحيث يمكن أن يميز logback إحدى الطرق عن طريقة أخرى ، قبل استدعاء الطريقة ، احفظ اسمه في سياق التشخيص المعيّن ThreadLocal . علاوة على ذلك ، أثناء التحليل ، لا نحصل على هذه القيم مباشرةً من فئة MDC ، حيث سيتم تنفيذ رمز التسجيل في سلسلة ILoggingEvent.getMDCPropertyMap() أخرى ولن تكون هذه البيانات موجودة - سنحصل عليها من خلال ILoggingEvent.getMDCPropertyMap() .


في الحالة العامة ، كما لاحظت vooft بشكل صحيح ، تحتاج إلى دعم مكدس الاستدعاءات وعدم الكتابة فوق قيمة MDC ، ولكن إعادتها إلى الإطار السابق ، والذي يتم من خلال إدخال ThreadLocal جديد. مثال تخطيطي:


  try { MDC.put(MDC_KEY_METHOD, currentMethod); // 1.  currentMethod    // 2.    // 3.       AOP, . } finally { String previousMethod = //     MDC.put(previousMethod); } 

ملف السجل الخاص لكل طريقة


لنقم بإنشاء ولا ننسى أن نسجل مستشارك الخاص بك:


  class MultiAppender extends AppenderBase<ILoggingEvent> { @Override protected void append(ILoggingEvent event) { method = event.getMDCPropertyMap().get(MDC_KEY_METHOD); Appender appender = getOrCreateAppender(method); appender.doAppend(event); } 

هو نفسه لا يفعل شيئًا تقريبًا ، فهو لا يقوم إلا بتفويض تسجيل الدخول إلى حزمة من مقدمي الملف الحقيقي ، واحد لكل طريقة. المفوض إلى واحد ، والأنسب. يتم إنشاء مقدمي "الحقيقي" عند الطلب ، على النحو التالي:


  fileAppender = new FileAppender<ILoggingEvent>(); fileAppender.setContext(lc); fileAppender.setAppend(false); fileAppender.setEncoder(getOrCreateEncoderByMethod(lc, method)); fileAppender.setFile(logFileByMethod.get(method)); fileAppender.start(); 

تنسيق خاص لكل طريقة


للقيام بذلك ، احتفظ بذاكرة التخزين المؤقت للكائنات التي تم إنشاؤها تلقائيًا من نوع Encoder :


  Map<String, String> patternByMethod = new HashMap<>(); //  ;  Encoder getOrCreateEncoderByMethod(LoggerContext lc, String method) { String pattern = patternByMethod.get(method); encoder = new PatternLayoutEncoder(); encoder.setContext(lc); encoder.setPattern(pattern); encoder.start(); return encoder; } 

كل طريقة لها مستوى التسجيل الخاص بها


نضيف فحصًا إلى فئة MultiAppender : إذا MultiAppender مستوى الحدث الحد المحدد للطريقة ، عندها فقط نقوم MultiAppender :


  Map<String, Level> levelByMethod = new HashMap<>(); protected void append(ILoggingEvent event) { Level minLevel = levelByMethod.get(methodName); if (event.getLevel().levelInt >= minLevel.levelInt) { appender.doAppend(event); } 

من حيث المبدأ ، يمكن وضع هذا المنطق في التصفية.


تمديد التنسيق مع المتغيرات الخاصة بك


حتى لا تقوم بتسييج حديقتك ، ولكن للاستفادة من البنية التحتية المثبتة لسجل الدخول ، تحتاج إلى تعريف فئة المحول الخاصة بك ، والتي هي عامة تمامًا بحيث يمكن إنشاء مثيل لها من الخارج. إذا كنت بحاجة إلى MDC ، MDC من الحدث. يبدأ معالج المتغير %custom هنا:


  public class CustomConverter extends ClassicConverter { public String convert(ILoggingEvent event) { // mdc = event.getMDCPropertyMap(); return "variable-expanded"; } } 

أثناء عملية التكوين العامة ، قم بتسجيل المعالج:


  void configurePatterns(LoggerContext lc) { Map<String, String> rules = lc.getObject(CoreConstants.PATTERN_RULE_REGISTRY); if (rules == null) { rules = new HashMap<String, String>(); lc.putObject(CoreConstants.PATTERN_RULE_REGISTRY, rules); } rules.put("custom", CustomConverter.class.getName()); } 

وسوف نستخدم PatternLayoutEncoder ، على سبيل المثال ، PatternLayoutEncoder ، والتي سوف تلتقط كل شيء. في هذه الحالة ، سيتم توسيع المتغير %custom في السلسلة "variable-expanded" .


تحديث التكوين على الطاير


هناك مثل هذه الفرصة خارج الصندوق: يكفي استدعاء وظيفة LoggerContext::reset() مرة أخرى ، دون أن ننسى القيام LoggerContext::reset() ومسح ذاكرة التخزين المؤقت المتراكمة.


خاصية تعدد


إذا نجحت الطريقة التي تم تكوينها بواسطتنا في إنشاء سلاسل رسائل جديدة ، فلن تسري عليها ، بالطبع ، قواعد التسجيل المحددة - لن تظهر سلاسل الصفحات المحلية بمفردها في سلسلة الرسائل الجديدة. لذلك ، إذا كنت ترغب في تطبيق إعدادات الطريقة على دفق جديد ، يجب عليك نسخ MDC هناك:


  Map<String, String> mdcOrig = MDC.getCopyOfContextMap(); ExecutorService es = Executors.newFixedThreadPool(1); es.submit(() -> threadWorker(mdcOrig)); void threadWorker(Map<String, String> parentMdc) { MDC.setContextMap(parentMdc); log.error("expected to appear in method2*.log"); } 

مثال كامل


https://github.com/zencd/logback-setup


أدب


دليل Logback الرسمي

Source: https://habr.com/ru/post/ar463601/


All Articles