
مهمة
دعنا نقول أننا أردنا تسجيل كل طريقة لفئة Java معينة بطريقة مختلفة:
- كل طريقة لها ملف السجل الخاص بها ،
- ... تنسيق السجل الخاص بك ،
- ... الحد الأدنى لمستوى التسجيل ،
- نقوم بتوسيع تنسيق السجل باستخدام
%
الخاصة بنا ، - القدرة على تحديث هذا التكوين على الطاير.
يوضح هذا المقال كيفية تلبية هذه المتطلبات. من أجل الحفاظ على البساطة ، لا يتم الفصل بين التسجيل إلا بالطرق ؛ في الواقع ، قد ترغب في الحصول على تهيئة مؤهلة للتسلسل الهرمي ، مثل
→
→
→
... سيكون الرابط إلى الكود المصدري الكامل أدناه.
كود العميل
class ThingService { log = LoggerFactory.getLogger(); getThing() { log.debug("getThing...");
Logback
للتنفيذ ، تم تحديد مكتبة تسجيل "logback" صلبة ، والتي توفر إمكانيات مثيرة للتخصيص:
ch.qos.logback:logback-classic:1.2.3
تم تكوينه من كلٍ من تهيئة XML ومباشرة من Java ، يمكن دمج الأساليب:
public void configureLogback() throws JoranException { LoggerContext lc = LoggerFactory.getILoggerFactory(); lc.reset();
باختصار حول التسجيل:
- مبرمج يسحب المسجل ،
- المسجل يسحب الملحقة المعينة له ،
- يفكر الملتزم ويدعو المشفر ،
- يقوم المشفر بتنسيق سطر واحد تمامًا من السجل ،
- للقيام بذلك ، يقوم بسحب سلسلة من المحولات ، كل منها يكشف عن
%
، - النجاح.
للبساطة ، تم اختيار تكوين جافا خالص. كل شيء واضح هنا إذا كنت تضع في الاعتبار تهيئة XML. تتمثل المهمة الرئيسية في إنشاء مرشد / مُشفّر خاص بك وتسجيله - سيتم استدعاءهم بواسطة logback من أحشاءهم. يجب تذكر كل كائن تقريبًا للبدء في استخدام طريقة start()
. مثال مجردة:
Logger rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); LoggerContext lc = rootLogger.getLoggerContext(); lc.reset();
افصل الطرق المسجلة عن بعضها البعض
بحيث يمكن أن يميز logback إحدى الطرق عن طريقة أخرى ، قبل استدعاء الطريقة ، احفظ اسمه في سياق التشخيص المعيّن ThreadLocal
. علاوة على ذلك ، أثناء التحليل ، لا نحصل على هذه القيم مباشرةً من فئة MDC
، حيث سيتم تنفيذ رمز التسجيل في سلسلة ILoggingEvent.getMDCPropertyMap()
أخرى ولن تكون هذه البيانات موجودة - سنحصل عليها من خلال ILoggingEvent.getMDCPropertyMap()
.
في الحالة العامة ، كما لاحظت vooft بشكل صحيح ، تحتاج إلى دعم مكدس الاستدعاءات وعدم الكتابة فوق قيمة MDC ، ولكن إعادتها إلى الإطار السابق ، والذي يتم من خلال إدخال ThreadLocal
جديد. مثال تخطيطي:
try { MDC.put(MDC_KEY_METHOD, currentMethod);
ملف السجل الخاص لكل طريقة
لنقم بإنشاء ولا ننسى أن نسجل مستشارك الخاص بك:
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<>();
كل طريقة لها مستوى التسجيل الخاص بها
نضيف فحصًا إلى فئة 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) {
أثناء عملية التكوين العامة ، قم بتسجيل المعالج:
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 الرسمي