2015-03-01 5 views
6

मैं एक वेब एप्लिकेशन लिखने की कोशिश कर रहा हूं जो रिमोट सर्वर पर चलाएगा। मुझे त्रुटियों/डीबग/ऑडिट कैप्चर करने के लिए लॉग इन करने की आवश्यकता है। मुझे लगता है कि मानक लॉग "पैकेज" सहित गोलांग के लिए एकाधिक लॉगिंग पैकेज उपलब्ध हैं। हालांकि, मैं तीन आवश्यकताओं को पूरा करने की जरूरत है:लॉग रोटेशन वाले फ़ाइल में मैं गोलांग में कैसे लॉग इन कर सकता हूं?

  1. लॉग फाइल घुमाया जा करने के लिए
  2. इसमें शामिल थे संकुल जो का उपयोग करें "लॉग ऑन"
  3. यह पार मंच की जरूरत है पर लागू होता है की जरूरत है। देव पर्यावरण लिनक्स है और विंडोज़ पर तैनात होने की जरूरत है।
+1

क्या आप स्पष्ट कर सकते हैं कि घूर्णन थोड़ा और क्या है? क्या यह प्रोग्राम शुरू हो रहा है, या जब फाइलें एक विशिष्ट आकार तक पहुंचती हैं, आदि? – klobucar

+1

पोस्टरिटी के लिए: मैं अत्यधिक lumberjack (https://github.com/natefinch/lumberjack) की सिफारिश करता हूं - जो मानक लाइब्रेरी के 'लॉग' पैकेज में 'log.SetOutput' के माध्यम से हुक करता है और लॉग रोटेशन, अधिकतम आकार और बैकअप बनाए रखता है। – elithrar

उत्तर

0

एक विकल्प है कि मन में आता है अपने स्वयं के प्रकार में प्रवेश रैप करने के लिए और एक बार पुनः लोड समारोह प्रदान करते हैं की तरह कुछ है: तो फिर

type Logger struct { 
    l *log.Logger 
    f *os.File 
    m sync.RWMutex 
} 

func NewLogger(fn string) (*Logger, error) { 
    f, err := os.Create(fn) 
    if err != nil { 
     return nil, err 
    } 
    l := &Logger{ 
     l: log.New(f, "your-app", log.Lshortfile), 
     f: f, 
    } 
    return l, nil 
} 

func (l *Logger) Logf(f string, args ...interface{}) { 
    l.m.RLock() 
    l.l.Printf(f, args...) 
    l.m.RUnlock() 
} 

func (l *Logger) Reload() (err error) { 
    l.m.Lock() 
    defer l.m.Unlock() 
    l.f.Close() 
    if l.f, err = os.Create(l.f.Name()); err != nil { 
     return 
    } 
    l.l = log.New(l.f, "your-app", log.Lshortfile) 
    return 
} 

या तो (* nix पर आमतौर पर -HUP) एक संकेत के लिए सुनने या अपने ऐप में एक एंडपॉइंट जोड़ें जो Logger.Reload() पर कॉल करेगा।

7

वैकल्पिक लॉगर स्ट्रक्चर बनाने की बजाय अपनी सभी तीन आवश्यकताओं को पूरा करने का सबसे अच्छा तरीका, यदि आप बेस-स्तरीय लॉग का उपयोग करके संतुष्ट थे। लॉग, लॉगर के आउटपुट को अपने स्वयं के io.Writer उदाहरण में सेट करने के बजाय है ।

तो मूल रूप से क्या मैं यहाँ क्या करने जा रहा हूँ मेरे अपने io.Writer एक उदाहरण मैं कहाँ बनाने दिखाने है:

import (
    "os" 
    "sync" 
    "time" 
) 

type RotateWriter struct { 
    lock  sync.Mutex 
    filename string // should be set to the actual filename 
    fp  *os.File 
} 

// Make a new RotateWriter. Return nil if error occurs during setup. 
func New(filename string) *RotateWriter { 
    w := &RotateWriter{filename: filename} 
    err := w.Rotate() 
    if err != nil { 
     return nil 
    } 
    return w 
} 

// Write satisfies the io.Writer interface. 
func (w *RotateWriter) Write(output []byte) (int, error) { 
    w.lock.Lock() 
    defer w.lock.Unlock() 
    return w.fp.Write(output) 
} 

// Perform the actual act of rotating and reopening file. 
func (w *RotateWriter) Rotate() (err error) { 
    w.lock.Lock() 
    defer w.lock.Unlock() 

    // Close existing file if open 
    if w.fp != nil { 
     err = w.fp.Close() 
     w.fp = nil 
     if err != nil { 
      return 
     } 
    } 
    // Rename dest file if it already exists 
    _, err = os.Stat(w.filename) 
    if err == nil { 
     err = os.Rename(w.filename, w.filename+"."+time.Now().Format(time.RFC3339)) 
     if err != nil { 
      return 
     } 
    } 

    // Create a file. 
    w.fp, err = os.Create(w.filename) 
    return 
} 

फिर आप एक RotateWriter बना सकते हैं और log.SetOutput का उपयोग इस लेखक स्थापित करने के लिए (अन्य पैकेजों अगर मानक लॉगर इंस्टेंस का उपयोग कर रहे हैं) या वैकल्पिक रूप से पास करने के लिए log.New का उपयोग करके अपने स्वयं के उदाहरण बनाएं।

मैंने रोटेट को कॉल करने की स्थिति को हल नहीं किया है, मैं इसे तय करने के लिए आपको छोड़ दूंगा। समय के आधार पर इसे ट्रिगर करने के लिए काफी सरल होगा, या कुछ मात्रा में लिखने या बाइट्स की कुछ मात्रा के बाद वैकल्पिक रूप से ऐसा करना होगा।

+1

मैं शायद 'sync.RWMutex' की बजाय' sync.Mutex' '(ए)' लॉग 'पैकेज पहले से ही धारावाहिक लिखने को संभालता है, इसलिए' RotateWriter.Write' के एकाधिक कॉलर्स का समर्थन करने से आपको कुछ भी नहीं मिलता है और (बी) जब तक कि आप 'os.O_APPEND' का उपयोग नहीं करते हैं, एक फ़ाइल में समवर्ती लिखना अनिर्धारित/खराब है। –

+0

अच्छा बिंदु, उदाहरण – Crast

+1

@Dave को ठीक करेगा ODAPPEND लिखने के साथ भी परमाणु होने की गारंटी नहीं दी जाती है जब तक कि लिखित डेटा PIPE_BUF के अंतर्गत न हो। – lethalman

3

यहाँ एक प्रकाश भारित प्रवेश पैकेज लॉग रोटेशन और ऑटो के शुद्धिकरण का समर्थन करता है

https://github.com/antigloss/go/tree/master/logger

// logger.Init must be called first to setup logger 
logger.Init("./log", // specify the directory to save the logfiles 
      400, // maximum logfiles allowed under the specified log directory 
      20, // number of logfiles to delete when number of logfiles exceeds the configured limit 
      100, // maximum size of a logfile in MB 
      false) // whether logs with Trace level are written down 
logger.Info("Failed to find player! uid=%d plid=%d cmd=%s xxx=%d", 1234, 678942, "getplayer", 102020101) 
logger.Warn("Failed to parse protocol! uid=%d plid=%d cmd=%s", 1234, 678942, "getplayer") 
+3

केवल लिंक लिंक ही सिफारिश नहीं की जाती है। स्पष्टीकरण के साथ कृपया कुछ उदाहरण प्रदान करें। – Nilambar

6

हालांकि @Crast एक बहुत अच्छा जवाब दिया है, मैं भी ध्यान में लाना चाहते हैं - lumberjackNate Finch द्वारा लॉगर जो मैंने उपयोग कर समाप्त किया।

इसका इस्तेमाल करने के लिए है:

  1. पहले क्लोन lumberjack भंडार या यह किसी भी तरह मिलता है।
  2. फ़ोल्डर पर go install आदेश चलाएं।
  3. अब जाओ "लॉग" पैकेज और "lumberjack पैकेज" आयात करें। मुख्य के बाहर,

अपनी लॉग चर घोषित: import ( "log" "github.com/natefinch/lumberjack" )

  • अब यह अपने कोड में इस तरह का उपयोग करें।

    var errLog *log.Logger 
    
    मुख्य अंदर

    :

    e, err := os.OpenFile("./foo.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 
    
        if err != nil { 
          fmt.Printf("error opening file: %v", err) 
          os.Exit(1) 
        } 
        errLog = log.New(e, "", log.Ldate|log.Ltime) 
        errLog.SetOutput(&lumberjack.Logger{ 
         Filename: "./foo.log", 
         MaxSize: 1, // megabytes after which new file is created 
         MaxBackups: 3, // number of backups 
         MaxAge:  28, //days 
        }) 
    

    अब जैसे ही फ़ाइल आकार प्राप्त 1 एमबी के रूप में, नई फ़ाइल वर्तमान टाइमस्टैम्प के साथ पिछले लॉग रखने के लिए बनाई गई है, और नए लॉग में लॉग इन करने के लिए जारी रहेगा foo.log फ़ाइल। साथ ही, मैंने os.OpenFile का उपयोग करके फ़ाइल बनाई है लेकिन आपको इसकी आवश्यकता नहीं हो सकती है क्योंकि लकड़ी के रूप में आंतरिक रूप से यह करता है, लेकिन मैंने इसे इस तरह से पसंद किया। धन्यवाद, उम्मीद है कि यह मदद करता है। एक बार फिर @Crast और NateFinch पर धन्यवाद।

  • +0

    मैंने लॉग रोलिंग के लिए उपरोक्त आपके उत्तर का प्रयास किया है लेकिन यह काम नहीं करता है। लॉग फ़ाइल निर्दिष्ट MaxSize पर रुक गई और इसे रोल किए बिना लॉगिंग बंद कर दी। मैं क्या खो रहा हूँ? – greenthunder

    +0

    @greenthunder क्या आपने मैक्सबैकअप को 1 से अधिक सेट किया था? – kinshuk4

    0

    https://github.com/jame2981/log मेरा पैकेज आपकी मदद कर सकता है।

    l1 := log.Pool.New("l1", "file:///tmp/test1.log") 
    l2 := log.Pool.New("l2", "file:///tmp/test2.log") 
    l3 := log.Pool.New("l3", "file:///tmp/test3.log") 
    l4 := log.Pool.New("l4", "file:///tmp/test4.log") 
    
    l1.Rotate() // rotate l1 only 
    log.Pool.Rotate() // was rotate all instances. 
    
    // rotate with signal 
    reopen := make(chan os.Signal, 1) 
    signal.Notify(reopen, syscall.SIGUSR1) 
    go func() { 
        for{ 
         <-reopen 
         l.Pool.Rotate() 
        } 
    }() 
    

    सेट std लॉगर लेखक अभी तक काम घुमाएं।

    // std logger writer 
    import "log" 
    logger := log.New("test", "", 0) 
    logger.SetOutput(l1.Writer()) 
    
    +0

    log.Logger.Writer किसी भी std लॉगर का उपयोग करें। – jame2981

    संबंधित मुद्दे