คุณจะค้นหา URL ใดที่ใช้ในการเริ่มต้นเริ่มต้นของ log4j ได้อย่างไร

การกำหนดค่าเริ่มต้นของ Log4j จะต้องผ่านขั้นตอนเพื่อค้นหาและใช้ URL เพื่อกำหนดค่า กับ. หลังจากนั้น คุณจะทราบได้อย่างไรว่าท้ายที่สุดแล้ว URL ใดที่ถูกใช้ โดยไม่ต้องเขียนโค้ดขั้นตอนเดียวกันด้วยตนเอง (หากคุณต้องเขียนโค้ดด้วยตัวเอง คุณอาจไม่ได้มันเหมือนกับที่ log4j ทำทุกประการ และอาจมีการเปลี่ยนแปลงในรุ่นต่อๆ ไป)


person skiphoppy    schedule 28.08.2012    source แหล่งที่มา


คำตอบ (4)


หากคุณยินดีที่จะใช้ AspectJ LTW (การทอผ้าตามเวลาโหลด) คุณสามารถดูการเริ่มต้นแบบคงที่ของ LogManager ที่ Ian Roberts กล่าวถึง ใน log4j 1.2.14 ดูเหมือนว่า:

static {
    // (...)
    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if (override == null || "false".equalsIgnoreCase(override)) {
        // (...)
        URL url = null;

        // (...)    
        // If we have a non-null url, then delegate the rest of the
        // configuration to the OptionConverter.selectAndConfigure method.
        if (url != null) {
            LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
            OptionConverter.selectAndConfigure(
                url, configuratorClassName, LogManager.getLoggerRepository()
            );
        } else {
            LogLog.debug("Could not find resource: [" + configurationOptionStr + "].");
        }
    }
}

แน่นอนว่าหากสามารถกำหนด URL เริ่มต้นได้ OptionConverter.selectAndConfigure(URL, ..) จะถูกเรียกที่จุดหนึ่งภายในบล็อกแบบคงที่เพื่อเริ่มต้น log4j ด้วย URL นั้น

ด้วยการใช้ AspectJ มันค่อนข้างง่ายที่จะตรวจจับการเรียกใช้เมธอดนั้น:

import java.net.URL;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.LogManager;

public aspect Log4jAspect {
    before(URL defaultURL) :
        within(LogManager) &&
        cflow(staticinitialization(LogManager)) &&
        call(* OptionConverter.selectAndConfigure(URL, ..)) &&
        args(defaultURL, ..)
    {
        System.out.println("log4j default URL = " + defaultURL);
    }
}

ในร้อยแก้วรหัสนี้หมายถึง:

  • หากเราอยู่ในคลาส LogManager และ
  • ภายในโฟลว์การควบคุมของการเริ่มต้นคลาสแบบคงที่และ
  • OptionConverter.selectAndConfigureถูกเรียกว่า
  • จากนั้นจับอาร์กิวเมนต์แรก (URL) และ
  • พิมพ์ไปที่คอนโซล (คุณสามารถทำอย่างอื่นได้เช่นกัน)

หากไม่มี URL เริ่มต้น จะไม่มีอะไรถูกพิมพ์ แทนที่จะพิมพ์ URL คุณสามารถกำหนดให้กับสมาชิกแบบคงที่ของชั้นเรียนใดก็ได้หรืออะไรก็ได้ที่คุณต้องการ

นี่เป็นวิธีแก้ไขปัญหาของคุณ ฉันทดสอบแล้วและใช้งานได้ ฉันยินดีที่จะได้รับเงินรางวัลจากการตอบคำถามของคุณ แม้ว่าโซลูชันอาจใช้เทคโนโลยีที่คุณไม่ได้คิดไว้ก็ตาม แต่มันแก้ปัญหาได้ :-)


แก้ไข: นอกจากนี้ยังสามารถสกัดกั้นการเรียกบันทึกได้อย่างชัดเจนในกรณีที่ไม่พบ URL เริ่มต้น แม้ว่าฉันคิดว่าไม่จำเป็นก็ตาม ฉันแค่อยากจะพูดถึงมัน

person kriegaex    schedule 30.08.2012
comment
คำตอบของคุณมีข้อมูลที่น่าอัศจรรย์ ขอบคุณ วิธีที่ยอดเยี่ยมในการเข้าถึงบางสิ่งที่เห็นได้ชัดว่าไม่สามารถทำได้อย่างที่ฉันต้องการ - person skiphoppy; 04.09.2012
comment
›1,000 ตัวแทนต่อวัน ประทับใจ :P - person Matthias; 05.09.2012

ขั้นตอนที่ใช้เป็นแบบฮาร์ดโค้ดในบล็อก Initializer แบบคงที่ใน LogManager ดังนั้นจึงดูเหมือนจะไม่มีวิธีใดที่จะเชื่อมโยงขั้นตอนดังกล่าวได้ ที่เดียวที่จะบอกคุณว่าเกิดอะไรขึ้นคือ

LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");

แต่ LogLog นั้นเป็นฮาร์ดโค้ดเพื่อใช้ System.out.println สำหรับข้อความเหล่านี้ ดังนั้นความเป็นไปได้เดียวที่ฉันเห็นคือเปิดการดีบัก (-Dlog4j.debug=true) และเชื่อมต่อกับ System.setOut ก่อนที่ log4j จะเริ่มต้น จากนั้นแยกวิเคราะห์ข้อความบันทึกการดีบัก แต่นั่นอาจจะเปราะบางกว่าการเขียนโค้ดขั้นตอนการกำหนดค่าด้วยตัวเองเสียอีก

ถึงกระนั้น ก็อาจมีการกำหนดค่าทางโปรแกรมอื่นๆ ที่ใช้หลังจากขั้นตอนการกำหนดค่าเริ่มต้น (เช่น Spring Log4jConfigListener) - ไม่จำเป็นต้องมี URL การกำหนดค่าเดียวเช่นนี้

มันอาจจะคุ้มค่าที่จะใส่คำขอคุณสมบัติ log4j เพื่อแยกโค้ดค้นหาไฟล์ config ออกเป็นวิธีการคงที่ที่คุณสามารถโทรจากที่อื่นได้ แต่นั่นจะไม่ช่วยอะไรเมื่อคุณอาจต้องรับมือกับ log4j เวอร์ชันก่อนหน้า

person Ian Roberts    schedule 30.08.2012

หากคุณสามารถตั้งค่า Configurator ของคุณเองได้ คุณสามารถดำเนินการดังนี้:

ตั้งค่าคุณสมบัติระบบ JAVA : -Dlog4j.configuratorClass=MyConfigurator จากนั้นให้อินสแตนซ์ตัวกำหนดค่าของคุณดักการเรียก doConfigure

public class MyConfigurator implements Configurator
{
    public static URL url;

    @Override
    public void doConfigure(URL url, LoggerRepository repository)
    {
        this.url = url;
        new PropertyConfigurator().doConfigure(url, repository);
    }
}
person Marc Polizzi    schedule 03.09.2012
comment
สิ่งนี้แนะนำแนวคิดที่ชาญฉลาดอีกอย่างหนึ่ง: การเอาชนะ Configurator โดยการแทรกของคุณเองไว้ก่อนหน้าใน classpath... - person skiphoppy; 04.09.2012

แทรกสิ่งนี้ลงในการโทร Java ของคุณ:

-Dlog4j.configDebug=true

นั่นคือทั้งหมดที่

person Mirko    schedule 31.08.2012
comment
ฉันกำลังมองหาวิธีที่โปรแกรมของฉันจะค้นหาข้อมูลนี้ - person skiphoppy; 31.08.2012