سؤال

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

بناءً على البلد الذي يأتي منه (أي.(الولايات المتحدة والمملكة المتحدة وفرنسا وما إلى ذلك) يقوم التطبيق بتشغيل مؤشر ترابط وظيفة واحد لتشغيل دورة المعالجة لكل بلد، لذلك سيكون هناك مؤشر ترابط للعامل في المملكة المتحدة، وواحد للولايات المتحدة وفرنسا وما إلى ذلك.عند تنسيق الإخراج إلى log4j، أستخدم معلمة مؤشر الترابط، لذلك يصدر [ApplicationName_Worker-1]، [ApplicationName_Worker-2] وما إلى ذلك.حاول قدر المستطاع، لا أستطيع العثور على طريقة لتسمية المواضيع نظرًا لأنه تم سحبها من تجمعات مؤشرات الترابط الخاصة بـ Quartz.على الرغم من أنه من الممكن أن أذهب إلى أبعد من ذلك لتوسيع الكوارتز، إلا أنني أرغب في التوصل إلى حل مختلف بدلاً من العبث بالمكتبة القياسية.

ها هي المشكلة:عند استخدام log4j، أرغب في تحويل جميع عناصر السجل من إخراج مؤشر الترابط الأمريكي إلى ملف أمريكي فقط، وكذلك الأمر بالنسبة لكل مؤشر ترابط في البلد.لا يهمني إذا بقوا في ConsoleAppender واحد موحد، فإن تقسيم FileAppender هو ما أسعى إليه هنا.أعرف بالفعل كيفية تحديد مُلحقات ملفات متعددة، ومشكلتي هي أنني لا أستطيع التمييز بناءً على البلد.يوجد أكثر من 20 فئة داخل التطبيق يمكن أن تكون في سلسلة التنفيذ، وعدد قليل جدًا منها أريد أن أثقل كاهله بمعرفة تمرير معلمة "سياق" إضافية من خلال كل طريقة...لقد فكرت في نمط إستراتيجية يوسع فئة غلاف log4j، ولكن ما لم أتمكن من السماح لكل فئة في السلسلة بمعرفة مؤشر الترابط الموجود لتحديد معلمات استدعاء المسجل، فإن هذا يبدو مستحيلاً.يؤدي عدم القدرة على تسمية سلسلة الرسائل أيضًا إلى خلق تحدي (وإلا سيكون ذلك سهلاً!).

إذن هذا هو السؤال:ما هو النهج المقترح للسماح للعديد من الفئات الثانوية في التطبيق والتي يتم استخدام كل منها لكل مؤشر ترابط مختلف لمعالجة الإدخال، مع العلم أنها ضمن سياق مؤشر ترابط بلد معين عند قيامهم بالتسجيل؟

حظا سعيدا في الفهم، ويرجى طرح أسئلة توضيحية!آمل أن يتمكن شخص ما من مساعدتي في اكتشاف طريقة مناسبة لمعالجة هذا الأمر.جميع الاقتراحات موضع ترحيب.

هل كانت مفيدة؟

المحلول

في الجزء العلوي من سلسلة المعالجة الخاصة بكل بلد، ضع رمز البلد في سياق التشخيص المعين (MDC) الخاص بـ Log4j.يستخدم هذا متغير ThreadLocal بحيث لا تضطر إلى تمرير البلد لأعلى ولأسفل مكدس الاستدعاءات بشكل صريح.ثم قم بإنشاء عامل تصفية مخصص ينظر إلى MDC، ويقوم بتصفية أي أحداث لا تحتوي على رمز البلد الحالي للمُلحق.

في الخاص بك Job:

...
public static final String MDC_COUNTRY = "com.y.foo.Country";
public void execute(JobExecutionContext context)
  /* Just guessing that you have the country in your JobContext. */
  MDC.put(MDC_COUNTRY, context.get(MDC_COUNTRY));
  try {
    /* Perform your job here. */
    ...
  } finally {
    MDC.remove(MDC_COUNTRY);
  }
}
...

اكتب العرف منقي:

package com.y.log4j;

import org.apache.log4j.spi.LoggingEvent;

/**
 * This is a general purpose filter. If its "value" property is null, 
 * it requires only that the specified key be set in the MDC. If its 
 * value is not null, it further requires that the value in the MDC 
 * is equal.
 */
public final class ContextFilter extends org.apache.log4j.spi.Filter {

  public int decide(LoggingEvent event) {
    Object ctx = event.getMDC(key);
    if (value == null)
      return (ctx != null) ? NEUTRAL : DENY;
    else
      return value.equals(ctx) ? NEUTRAL : DENY;
  }

  private String key;
  private String value;

  public void setContextKey(String key) { this.key = key; }
  public String getContextKey() { return key; }
  public void setValue(String value) { this.value = value; }
  public String getValue() { return value; }

}

في log4j.xml الخاص بك:

<appender name="fr" class="org.apache.log4j.FileAppender">
  <param name="file" value="france.log"/>
  ...
  <filter class="com.y.log4j.ContextFilter">
    <param name="key" value="com.y.foo.Country" />
    <param name="value" value="fr" />
  </filter>
</appender> 

نصائح أخرى

أتمنى أن أكون أكثر فائدة من هذا، ولكن قد ترغب في التحقق من استخدام بعض المرشحات؟ربما يمكن أن يؤدي تسجيلك إلى إخراج رمز البلد ويمكنك مطابقة الفلتر الخاص بك بناءً على ذلك؟

من المحتمل أن يكون StringMatchFilter قادرًا على مطابقته لك.

تعذر جعل العنوان أدناه يعمل بشكل صحيح كارتباط، ولكن إذا نظرت إليه، فستجد أنه يحتوي على بعض الأشياء في تسجيل ملف منفصل باستخدام عوامل التصفية.

http://mail-archives.Apache.org/mod_mbox/logging-log4j-user/200512.mbox/<1CC26C83B6E5AA49A9540FAC8D35158B01E2968E@pune.kaleconsultants.com > (فقط قم بإزالة المسافة قبل >)

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/spi/Filter.html

لماذا لا تتصل فقط بـ Thread.setName() عندما تبدأ مهمتك في تعيين اسم الموضوع؟إذا كانت هناك مشكلة في الوصول، فقم بتكوين الكوارتز لاستخدام مجموعة الخيوط الخاصة بك.

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

  1. قم بإعداد مُلحق في تكوين log4j الخاص بك لكل بلد ترغب في تسجيل الدخول إليه بشكل منفصل (يتوفر مثال أمريكي):

    log4j.appender.usfile=org.apache.log4j.FileAppender

    log4j.appender.usfile.File=us.log

    log4j.appender.usfile.layout=org.apache.log4j.PatternLayout

    log4j.appender.usfile.layout.ConversionPattern=%m%n

  2. قم بإنشاء مسجل لكل بلد وقم بتوجيه كل منهم إلى المُلحق المناسب (يتوفر مثال أمريكي):

    log4j.logger.my-us-logger=debug,usfile

  3. في التعليمات البرمجية الخاصة بك، قم بإنشاء المسجل الخاص بك بناءً على البلد الذي تتم معالجة البريد الإلكتروني فيه:

    المسجل logger = Logger.getLogger("my-us-logger");

  4. حدد كيفية إنجاز الخطوة 3 لاستدعاءات الطريقة اللاحقة.يمكنك تكرار الخطوة 3 في كل فئة/طريقة؛أو يمكنك تعديل توقيعات الطريقة لقبول المسجل كمدخل؛أو ربما يمكنك استخدام ThreadLocal لتمرير المسجل بين الطرق.

معلومات اضافية:إذا كنت لا تريد أن تنتقل بيانات السجل إلى المسجلين الرئيسيين (على سبيل المثال.rootLogger)، يمكنك ضبط علامات الإضافة الخاصة بهم على false (تم توفير مثال أمريكي):

log4j.additivity.my-us-logger=false
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top