2008-10-11 4 views
27

मैं मानक ConsoleHandlerjava.util.logging से और डिफ़ॉल्ट रूप से सांत्वना उत्पादन त्रुटि धारा को निर्देश दिया जाता है (यानी System.err) का उपयोग कर रहा हूँ।मैं std err से std out में जावा लॉगिंग कंसोल आउटपुट कैसे बदलूं?

मैं उत्पादन धारा (अर्थात System.out) को सांत्वना उत्पादन बदल सकता हूँ?

उत्तर

3

के लिए दस्तावेज़ और स्रोत पर एक नज़र डालें - मुझे यकीन है कि आप आसानी से एक संस्करण लिख सकते हैं जो System.out के बजाय System.err का उपयोग करता है। (यह एक शर्म की बात है कि कंसोल हैंडलर इसे ईमानदार होने के लिए कॉन्फ़िगर करने की अनुमति नहीं देता है।)

फिर यह सामान्य तरीके से अपने नए स्टडआउट हैंडलर (या जिसे आप इसे कहते हैं) का उपयोग करने के लिए लॉगिंग सिस्टम को कॉन्फ़िगर करने का एक मामला है ।

उदाहरण के लिए, फ़ाइलों के लिए:

+0

मुझे लगता है कि कंसोलहैंडलर डिफ़ॉल्ट है, स्ट्रीमहैंडलर है जो किसी भी अन्य स्ट्रीम पर प्रिंट कर सकता है। – Uri

+3

हां, लेकिन आप StreamHandler को उपclass करना चाहते हैं ताकि System.err को बंद करने का प्रयास करने से बचने के लिए, मुझे संदेह है। –

1

आप जावा प्रवेश का उपयोग करते हैं, तो आप डिफ़ॉल्ट प्रबंधक को बदल सकते हैं हैंडलर एफ एच = नए FileHandler (FILENAME); Logger.getLogger (LOGGER_NAME) .addHandler (एफ एच);

यदि आप स्ट्रीम में आउटपुट करना चाहते हैं तो आप StreamHandler का उपयोग कर सकते हैं, मुझे लगता है कि आप इसे सिस्टम स्ट्रीम समेत किसी भी आउटपुट स्ट्रीम के साथ कॉन्फ़िगर कर सकते हैं।

7

मैं एक तरीका खोज निकाला। सबसे पहले डिफ़ॉल्ट सांत्वना प्रबंधक को निकाल:

setUseParentHandlers (गलत);

फिर ConsoleHandler उपवर्ग और निर्माता में:

setOutputStream (System.out);

+3

'setOutputStream (...)' या 'LogManager.reset()' पर अगली कॉल पर इसे बंद करने से बचने के लिए आप स्वयं लागू 'आउटपुटस्ट्रीम' के साथ 'System.out' को बेहतर तरीके से लपेटें। – amotzg

+0

इसके अलावा, सुपर कन्स्ट्रक्टर ('कंसोल हैंडलर'' को कॉल करने के लिए सावधानी बरतें क्योंकि यह System.err सेट करता है और आप 'setOutputStream (System.out)' को कॉल करते समय इसे बंद कर देंगे। या, आप केवल 'स्ट्रीमहैंडलर' को उपclass कर सकते हैं और 'सुपर (आउटपुटस्ट्रीम, फॉर्मेटर)' कॉल कर सकते हैं। – amotzg

0

आप setUseParentHandlers (गलत) सेट करते हैं; केवल वह वर्ग सेट है। ऐप में अन्य कक्षाएं अभी भी इसे stderr के माध्यम से पास कर देगी।

+0

यदि कोई रूट लॉगिंग क्लास (Logger.GLOBAL_LOGGER_NAME) के लिए करता है, तो सभी वर्गों के लिए कंसोल लॉगिंग अक्षम है। – koppor

-1

बस कन्स्ट्रक्टर कॉल सुपर (System.out,) में StreamHandler & का विस्तार करें। यह System.err बंद करने से दूर रहेंगे - धन्यवाद

9
Handler consoleHandler = new Handler(){ 
     @Override 
      public void publish(LogRecord record) 
      { 
       if (getFormatter() == null) 
       { 
        setFormatter(new SimpleFormatter()); 
       } 

       try { 
        String message = getFormatter().format(record); 
        if (record.getLevel().intValue() >= Level.WARNING.intValue()) 
        { 
         System.err.write(message.getBytes());      
        } 
        else 
        { 
         System.out.write(message.getBytes()); 
        } 
       } catch (Exception exception) { 
        reportError(null, exception, ErrorManager.FORMAT_FAILURE); 
       } 

      } 

      @Override 
      public void close() throws SecurityException {} 
      @Override 
      public void flush(){} 
     }; 
+6

लेकिन, आधुनिक दिनों में ... कस्टम हैंडलर को लागू किए बिना ऐसा करने का कोई तरीका है ?? – Victor

10

मैं आ चुके पैर में

SimpleFormatter fmt = new SimpleFormatter(); 
StreamHandler sh = new StreamHandler(System.out, fmt); 
logger.addHandler(sh); 
+1

यह डिफ़ॉल्ट हैंडलर को अक्षम नहीं करता है। बस उत्तर का पालन करें http://stackoverflow.com/a/2533250/873282 – koppor

7

हम्म मैं बस मिल गया बिट में कुछ समय में, यह उपलब्धि हासिल करने की कोशिश कर रहा। यहां मेरे रास्ते पर जाने से पहले मैं निम्नलिखित हैक को स्वीकार करने में कामयाब रहा। बदसूरत, लेकिन ऐसा लगता है कि काम पूरा हो गया।

public class StdoutConsoleHandler extends ConsoleHandler { 
    protected void setOutputStream(OutputStream out) throws SecurityException { 
    super.setOutputStream(System.out); // kitten killed here :-(
    } 
} 

ध्यान दें: कॉलिंग setOutputStream() से निर्माता आकर्षक है, लेकिन यह करता है करीब System.err (के रूप में जॉन स्कीट पहले ही बताया)। मैड स्किल्स!

2

यदि कोई समस्या है तो इस समस्या का हल ढूंढ रहे हैं। यहां मैं आखिरकार आया था: मैंने बस स्ट्रीमहैंडलर को उपclassed और अतिरिक्त पैरामीटर मैक्सलेवल जोड़ा, जिसे प्रकाशित() की शुरुआत में चेक किया गया है। यदि लॉगिंग ईवेंट का स्तर मैक्सलेवल से बड़ा है, तो प्रकाशित नहीं किया जाएगा।

MaxlevelStreamHandler.java मुख्य नीचे वर्ग: यहाँ विवरण हैं।

package helper; 

/** 
* The only difference to the standard StreamHandler is 
* that a MAXLEVEL can be defined (which then is not published) 
* 
* @author Kai Goergen 
*/ 

import java.io.PrintStream; 
import java.util.logging.Formatter; 
import java.util.logging.Level; 
import java.util.logging.LogRecord; 
import java.util.logging.StreamHandler; 

public class MaxlevelStreamHandler extends StreamHandler { 

    private Level maxlevel = Level.SEVERE; // by default, put out everything 

    /** 
    * The only method we really change to check whether the message 
    * is smaller than maxlevel. 
    * We also flush here to make sure that the message is shown immediately. 
    */ 
    @Override 
    public synchronized void publish(LogRecord record) { 
     if (record.getLevel().intValue() > this.maxlevel.intValue()) { 
      // do nothing if the level is above maxlevel 
     } else { 
      // if we arrived here, do what we always do 
      super.publish(record); 
      super.flush(); 
     } 
    } 

    /** 
    * getter for maxlevel 
    * @return 
    */ 
    public Level getMaxlevel() { 
     return maxlevel; 
    } 

    /** 
    * Setter for maxlevel. 
    * If a logging event is larger than this level, it won't be displayed 
    * @param maxlevel 
    */ 
    public void setMaxlevel(Level maxlevel) { 
     this.maxlevel = maxlevel; 
    } 

    /** Constructor forwarding */ 
    public MaxlevelStreamHandler(PrintStream out, Formatter formatter) { 
     super(out, formatter); 
    } 

    /** Constructor forwarding */ 
    public MaxlevelStreamHandler() { 
     super(); 
    } 
} 

मुख्य क्लास

अब stdout में कुछ घटनाओं और दिखाने के लिए stderr में कुछ, बस सेटअप दो StreamLoggers, महत्वपूर्ण घटनाओं के लिए एक और अन्य सभी के लिए एक है, और मानक सांत्वना लकड़हारा निष्क्रिय कर दें:

// setup all logs that are smaller than WARNINGS to stdout 
MaxlevelStreamHandler outSh = new MaxlevelStreamHandler(System.out, formatter); 
outSh.setLevel(Level.ALL); 
outSh.setMaxlevel(Level.INFO); 
logger.addHandler(outSh); 

// setup all warnings to stdout & warnings and higher to stderr 
StreamHandler errSh = new StreamHandler(System.err, formatter); 
errSh.setLevel(Level.WARNING); 
logger.addHandler(errSh); 

// remove default console logger 
logger.setUseParentHandlers(false); 

logger.info("info"); 
logger.warning("warning"); 
logger.severe("severe"); 

आशा है कि इससे मदद मिलती है!

अपडेट: मैंने सुपर.publish() के बाद super.flush() को सही ढंग से जोड़ा है ताकि यह सुनिश्चित किया जा सके कि संदेश तुरंत दिखाया गया है। इससे पहले, मुझे समस्याएं थीं कि लॉग-मैसेज हमेशा अंत में दिखाए जाते थे। यह अब उपरोक्त कोड का हिस्सा है।

2

मुझे एक ही समस्या थी। मैं INFO और नीचे System.out, और चेतावनी और ऊपर System.err पर लॉग इन करना चाहता था।

public class DualConsoleHandler extends StreamHandler { 

    private final ConsoleHandler stderrHandler = new ConsoleHandler(); 

    public DualConsoleHandler() { 
     super(System.out, new SimpleFormatter()); 
    } 

    @Override 
    public void publish(LogRecord record) { 
     if (record.getLevel().intValue() <= Level.INFO.intValue()) { 
      super.publish(record); 
      super.flush(); 
     } else { 
      stderrHandler.publish(record); 
      stderrHandler.flush(); 
     } 
    } 
} 
बेशक

, आप इसे अधिक Level.INFO को हार्ड-कोडेड संदर्भ बाहर बाँटे, उदाहरण के लिए द्वारा लचीला बना सकता है: यहाँ समाधान मैं लागू किया है। लेकिन यह मेरे लिए कुछ बुनियादी दोहरी धारा लॉगिंग प्राप्त करने के लिए अच्छा काम किया। (Btw, ConsoleHandler बंद करने System.err बहुत उपयोगी थे से बचने के लिए उपवर्गीकरण नहीं के बारे में सुझाव दिए गए।)

+0

बिल्कुल सही। कहा जाना चाहिए कि डिजाइनरों ने वास्तव में इसे आसान नहीं बनाया है ... वे इस आवश्यकता की अपेक्षा क्यों नहीं कर सकते? आपको लगता है कि यह अन्य लॉगिंग ढांचे के साथ समान लगता है: आपका पहला काम? कई मुश्किल हुप्स के माध्यम से कूदो! –

1

ConsoleHandler निर्माण के दौरान System.err का एक स्नैपशॉट हड़पने होगा। एक विकल्प ग्लोबल एरर स्ट्रीम को वैश्विक आउट स्ट्रीम के साथ स्वैप करना होगा और फिर कंसोल हैंडलर बनाएं।

final PrintStream err = System.err; 
System.setErr(System.out); 
ConsoleHandler h = new ConsoleHandler(); //Snapshot of System.err 
System.setErr(err); 

यह मानता है कि कोड में त्रुटि स्ट्रीम को संशोधित करने की अनुमति है और कोई अन्य रनिंग कोड त्रुटि स्ट्रीम तक नहीं पहुंच रहा है। संक्षेप में, यह एक विकल्प है लेकिन सुरक्षित विकल्प हैं।

1

जब हम एक नया कंसोल हैंडलर ऑब्जेक्ट बनाते हैं, तो डिफ़ॉल्ट आउटपुट स्ट्रीम "system.err" है। अफसोस की बात है कि जावा आउटपुट स्ट्रीम सेट करने के लिए ConsoleHandler क्लास के लिए कोई सार्वजनिक विधि प्रदान नहीं करता है। तो यह केवल वस्तु निर्माण के समय सेट किया जा सकता है। कंसोल हैंडलर क्लास StreamHandler को बढ़ाता है, जिसमें स्पष्ट रूप से आउटपुट स्ट्रीम सेट करने के लिए "setOutputStream" संरक्षित विधि है। कंसोल हैंडलर के लिए आउटपुट स्ट्रीम सेट करने के लिए ऑब्जेक्ट सृजन के लिए नई कॉल के समय इस विधि को ओवरराइड करें।

ConsoleHandler consoleHandler = new ConsoleHandler(){ 
      @Override 
      protected synchronized void setOutputStream(OutputStream out) throws SecurityException { 
       super.setOutputStream(System.out); 
      } 
     }; 
संबंधित मुद्दे