การเปลี่ยนระดับการบันทึก log4j แบบไดนามิก


127

วิธีต่างๆในการเปลี่ยนระดับบันทึก log4j แบบไดนามิกมีอะไรบ้างเพื่อที่ฉันจะได้ไม่ต้องปรับใช้แอปพลิเคชันอีกครั้ง การเปลี่ยนแปลงจะถาวรในกรณีเหล่านี้หรือไม่?



คล้ายกันมากกับstackoverflow.com/questions/2115900/…
vsingh

3
อัปเดตคำถามสำหรับ log4j2: stackoverflow.com/questions/23434252/…
slaadvak

1
โปรดทราบว่า (เกือบ) ทุกอย่างในหน้านี้เกี่ยวกับ log4j ไม่ใช่ log4j2 ทั้งหน้านี้เต็มไปด้วยความสับสนและทิศทางที่ไม่ถูกต้องจนไม่มีประโยชน์ ไปที่stackoverflow.com/questions/23434252/…ตามที่ @slaadvak แนะนำ
Lambart

คำตอบ:


86

การเปลี่ยนระดับการบันทึกเป็นเรื่องง่าย การแก้ไขส่วนอื่น ๆ ของการกำหนดค่าจะก่อให้เกิดแนวทางเชิงลึกมากขึ้น

LogManager.getRootLogger().setLevel(Level.DEBUG);

การเปลี่ยนแปลงจะถาวรตลอดชีวิตของLogger. ในการกำหนดค่าเริ่มต้นใหม่การกำหนดค่าจะถูกอ่านและใช้เป็นการตั้งค่าระดับที่รันไทม์ไม่เปลี่ยนแปลงระดับ

UPDATE:หากคุณใช้ Log4j 2 คุณควรลบการโทรออกsetLevelตามเอกสารประกอบเพราะสามารถทำได้ผ่านคลาสการใช้งาน

API ไม่รองรับการเรียก logger.setLevel () หรือวิธีการที่คล้ายกัน แอปพลิเคชันควรลบสิ่งเหล่านี้ออก ฟังก์ชันการทำงานเทียบเท่ามีให้ในคลาสการใช้งาน Log4j 2 แต่อาจทำให้แอปพลิเคชันมีความอ่อนไหวต่อการเปลี่ยนแปลงใน Log4j 2 ภายใน


5
สำหรับการพึ่งพารันไทม์เท่านั้นLogManager.getLogger(Class.forName("org.hibernate.util.JDBCExceptionReporter")).setLevel(Level.FATAL);
CelinHC

8
โปรดทราบว่า log4j 2 API ไม่มีเมธอด "setLevel"
ChrisCantrell

5
แต่นี่เป็นการตั้งค่า root logger เท่านั้นใช่หรือไม่? หากมีการตั้งค่าแต่ละระดับสำหรับคนตัดไม้ภายใต้รูทการตั้งค่าตัวตัดไม้รากจะไม่มีผลกับ LOGGER เหล่านั้น เราจะไม่ต้องทำอะไรเช่น root.getLoggerRepository (). getCurrentCategories () วนซ้ำในแต่ละอินสแตนซ์ของคนตัดไม้และตั้งค่า LEVEL สำหรับคนตัดไม้แต่ละคนหรือไม่? @AaronMcIver
TheMonkWhoSoldHisCode

8
@ChrisCantrell Log4j 2 มีวิธีการทำแม้ว่ามันจะไม่ง่ายเท่า
CorayThan

2
Log4j2 สามารถกำหนดค่าให้รีเฟรชคอนฟิกูเรชันโดยการสแกนไฟล์ log4j2.xml (หรือเทียบเท่า) ตามช่วงเวลาที่กำหนด เช่น <Configuration status = "warn" monitorInterval = "5" name = "tryItApp" Packages = "">
Kimball Robinson

89

ไฟล์ Watchdog

Log4j สามารถดูlog4j.xmlไฟล์สำหรับการเปลี่ยนแปลงการกำหนดค่า หากคุณเปลี่ยนไฟล์ log4j log4j จะรีเฟรชระดับการบันทึกโดยอัตโนมัติตามการเปลี่ยนแปลงของคุณ ดูเอกสารของorg.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long) สำหรับรายละเอียด เวลารอเริ่มต้นระหว่างการตรวจสอบคือ 60 วินาที การเปลี่ยนแปลงเหล่านี้จะคงอยู่เนื่องจากคุณเปลี่ยนไฟล์คอนฟิกูเรชันบนระบบไฟล์โดยตรง สิ่งที่คุณต้องทำคือเรียกใช้ DOMConfigurator.configureAndWatch () หนึ่งครั้ง

ข้อควรระวัง: วิธีการ configAndWatch ไม่ปลอดภัยสำหรับการใช้งานในสภาพแวดล้อม J2EE เนื่องจากเธรดรั่ว

JMX

อีกวิธีหนึ่งในการตั้งค่าระดับการบันทึก (หรือกำหนดค่าใหม่โดยทั่วไป) log4j คือการใช้ JMX Log4j ลงทะเบียนคนตัดไม้เป็น JMX MBeans การใช้แอปพลิเคชันเซิร์ฟเวอร์คอนโซล MBeanServer (หรือ jconsole.exe ของ JDK) คุณสามารถกำหนดค่าตัวบันทึกแต่ละตัวใหม่ได้ การเปลี่ยนแปลงเหล่านี้ไม่คงอยู่และจะถูกรีเซ็ตเป็นการกำหนดค่าตามที่ตั้งไว้ในไฟล์คอนฟิกูเรชันหลังจากที่คุณรีสตาร์ทแอปพลิเคชัน (เซิร์ฟเวอร์)

ที่สร้างตัวเอง

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


8
คำเตือนเกี่ยวกับแนวทางการเฝ้าระวัง log4j: "เนื่องจาก configureAndWatch เปิดใช้เธรด watchdog แยกต่างหากและเนื่องจากไม่มีวิธีหยุดเธรดนี้ใน log4j 1.2 เมธอด configAndWatch จึงไม่ปลอดภัยสำหรับการใช้งานในสภาพแวดล้อม J2EE ที่มีการรีไซเคิลแอปพลิเคชัน" อ้างอิง: Log4J FAQ
Somu

ถ้าฉันจะใช้ฟังก์ชัน configureAndWatch ของ Log4j ฉันสามารถหยุดเธรด watchdog นั้นได้ในเมธอด @PostDestroy ของ EJB (นั่นเป็นตัวบ่งชี้ที่ดีพอว่าเมื่อใดที่คอนเทนเนอร์กำลังปิดตัวลง) หรือมีอะไรมากกว่านั้นที่ฉันหายไป .. !
robin bajaj

ขอโทษฉันหมายถึงวิธี @PreDestroy
robin bajaj

" Log4j ลงทะเบียนคนตัดไม้เป็น JMX MBeans " servlet ของฉันใช้ log4j 1.2 ฉันไม่เห็น log4j MBeans ใด ๆ
อับดุล

สิ่งที่คุณต้องทำคือเรียกใช้ DOMConfigurator.configureAndWatch () หนึ่งครั้ง ฉันจะบรรลุเป้าหมายนี้ได้อย่างไร?
gstackoverflow

5

Log4j2 สามารถกำหนดค่าเพื่อรีเฟรชคอนฟิกูเรชันโดยการสแกนไฟล์ log4j 2 .xml (หรือเทียบเท่า) ตามช่วงเวลาที่กำหนด เพียงเพิ่มพารามิเตอร์ " monitorInterval " ลงในแท็กการกำหนดค่าของคุณ ดูบรรทัดที่ 2 ของไฟล์log4j 2 .xml ตัวอย่างซึ่งบอกให้ log4j สแกนการกำหนดค่าอีกครั้งหากผ่านไปนานกว่า 5 วินาทีนับตั้งแต่เหตุการณ์บันทึกล่าสุด

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

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


@vsingh คุณกำลังปรับใช้ในสปริงบูตทอมแคทหรือคอนเทนเนอร์หรือกับ IDE? บางครั้งอาจมีขั้นตอนเพิ่มเติมในกรณีเหล่านี้ (ไม่ใช่ข้อผิดพลาดของ log4j2) - โดยพื้นฐานแล้วแอปจะไม่เห็นไฟล์ที่เปลี่ยนแปลงเนื่องจากถูกคัดลอกไปยังตำแหน่งอื่นโดยเฟรมเวิร์กหรือเครื่องมือ
Kimball Robinson

สวัสดีฉันทดสอบสิ่งนี้บน Jboss6.4 และฉันอัปเดตไฟล์ config log4j2 ภายใต้ตำแหน่ง (ภายในไฟล์. war) ซึ่งแอปสามารถมองเห็นไฟล์ได้ อย่างไรก็ตามมันก็ยังไม่ได้ผล ข้อเสนอแนะใด ๆ ?
MidTierDeveloper

3

คำตอบนี้จะไม่ช่วยให้คุณเปลี่ยนระดับการบันทึกแบบไดนามิกคุณต้องเริ่มบริการใหม่หากคุณเริ่มบริการใหม่ได้ดีโปรดใช้วิธีแก้ไขปัญหาด้านล่าง

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

ส่งผ่านสิ่งนี้เป็นพารามิเตอร์ JVM (ฉันใช้ Java 1.7)

ขออภัยสิ่งนี้จะไม่เปลี่ยนระดับการบันทึกแบบไดนามิกจำเป็นต้องเริ่มบริการใหม่

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

ในไฟล์ log4j.properties ฉันเพิ่มรายการนี้

log4j.rootLogger=${logging.level},file,stdout

ฉันเหนื่อย

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

ทุกอย่างได้ผล หวังว่านี่จะช่วยได้!

ฉันมีการอ้างอิงต่อไปนี้ใน pom.xml ของฉัน

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>

2
สิ่งที่คุณพูดถึงดูเหมือนจะดี แต่คำถามคือเกี่ยวกับการเปลี่ยนระดับการบันทึกแบบไดนามิก
Azim

ในการดำเนินการนี้คุณต้องเริ่มบริการใหม่ ซึ่งไม่ได้เปลี่ยนระดับการบันทึกแบบไดนามิก
kk.

2

ด้วย log4j 1.x ฉันพบวิธีที่ดีที่สุดคือการใช้ DOMConfigurator เพื่อส่งชุดการกำหนดค่าบันทึก XML ที่กำหนดไว้ล่วงหน้า (เช่นหนึ่งชุดสำหรับการใช้งานปกติและอีกชุดหนึ่งสำหรับการดีบัก)

การใช้สิ่งเหล่านี้สามารถทำได้ด้วยสิ่งนี้:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

เพียงแค่เรียกสิ่งนี้ด้วยชื่อการกำหนดค่าที่เหมาะสมและตรวจสอบให้แน่ใจว่าคุณได้ใส่แม่แบบบน classpath


อะไรคือจุดเริ่มต้นของวิธีนี้? จะรู้ได้อย่างไรว่าต้องเรียกใช้วิธีนี้เมื่อใดก็ตามที่มีการเปลี่ยนแปลงในการกำหนดค่า log4j
asgs

ฉันยังไม่เข้าใจสิ่งที่คุณหมายถึง "ตามคำขอ" คุณช่วยแสดงตัวอย่างที่คุณใช้วิธีนี้ได้ไหม
asgs

2
จัดให้เลย: นี่คือตัวอย่างข้อมูลจากคอนโทรลเลอร์ที่เราใช้งาน เรามีหน้าผู้ดูแลระบบที่มีลิงก์บางส่วนเพื่อกำหนดค่าการบันทึกใหม่แบบไดนามิกซึ่งจะทำให้ GET ไปยังลิงก์ / admin / setLogLevel? level = Error จากนั้นเราจะจับสิ่งนี้ในคอนโทรลเลอร์เช่น @RequestMapping (value = "setLogLevel", method = RequestMethod.GET) ModelAndView สาธารณะ setLogLevel (@RequestParam (value = "level", required = true) ระดับ String) {Log4jReconfigurator.reconfigureExisting (ระดับ);
ISparkes

ดังนั้น "ตามคำขอ" จึงหมายถึง "เมื่อผู้ใช้คลิกปุ่ม" ในกรณีของฉัน
ISparkes

อามีคุณ ดังนั้นคอนโซลผู้ดูแลระบบของคุณจึงต้องร้องขอเพื่อเรียกใช้วิธีนี้
asgs

0

ฉันใช้วิธีนี้อย่างประสบความสำเร็จเพื่อลดความฟุ่มเฟื่อยของบันทึก "org.apache.http":

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);

0

สำหรับ log4j 2 API คุณสามารถใช้ไฟล์

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));

-1

หากคุณต้องการเปลี่ยนระดับการบันทึกของคนตัดไม้ทั้งหมดให้ใช้วิธีการด้านล่าง สิ่งนี้จะแจกแจงเกี่ยวกับคนตัดไม้ทั้งหมดและเปลี่ยนระดับการบันทึกเป็นระดับที่กำหนด โปรดตรวจสอบว่าคุณไม่ได้log4j.appender.loggerName.Threshold=DEBUGตั้งค่าคุณสมบัติไว้ในlog4j.propertiesไฟล์ของคุณ

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}

-3

คุณสามารถใช้ข้อมูลโค้ดต่อไปนี้

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));

ฉันต้องลอง
user2045474
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.