2016-06-21 15 views
8

मेरे पास एक ऐसा एप्लिकेशन है जो बहु-थ्रेडिंग का उपयोग करता है और सर्वर पर पृष्ठभूमि में चलाया जाता है। सर्वर पर लॉग ऑन किए बिना एप्लिकेशन की निगरानी करने के लिए, मैंने कुछ HTTP अंतराल और रिपोर्ट स्थिति का जवाब देने के लिए Bottle शामिल करने का निर्णय लिया, रिमोट शटडाउन आदि का प्रदर्शन किया।एक चर के लिए पायथन रोलिंग लॉग

मैं भी एक रास्ता जोड़ना चाहता था लॉगफाइल से परामर्श करने के लिए। मैं FileHandler का उपयोग करके लॉग इन कर सकता हूं और यूआरएल अनुरोधित होने पर गंतव्य फ़ाइल भेज सकता हूं (उदा। /log)।

हालांकि, मैं सोच रहा था कि RotatingFileHandler जैसे कुछ को कार्यान्वित करना संभव होगा, लेकिन फ़ाइल में लॉगिंग करने के बजाय, एक चर (जैसे BytesIO) पर लॉग इन करना। इस तरह, मैं लॉग को नवीनतम जानकारी तक सीमित कर सकता हूं, जबकि साथ ही इसे एक अलग फ़ाइल डाउनलोड के बजाय ब्राउज़र में पाठ के रूप में वापस करने में सक्षम होना चाहिए।

RotatingFileHandler को एक फ़ाइल नाम की आवश्यकता है, इसलिए यह BytesIO स्ट्रीम पास करने का विकल्प नहीं है। एक चर के लिए लॉगिंग पूरी तरह से करने योग्य है (उदा। Capturing Python Log Output In A Variable), लेकिन मैं रोलिंग भाग को कैसे करना है, इस पर थोड़ा सा स्टंप हूं।

कोई भी विचार, संकेत, सुझावों की बहुत सराहना की जाएगी।

+1

आप एक 'collections.deque' वस्तु का इस्तेमाल कर सकता लॉग आउटपुट को कैप्चर करने के लिए? आप डेक के लिए अधिकतम लंबाई निर्धारित करेंगे, और एक बार यह इस लंबाई तक पहुंचने के बाद पुराने लॉग आइटम शुरू हो जाएंगे क्योंकि आप नए लॉग आइटम जोड़ते हैं। –

उत्तर

1

एंड्रयू लड़का के सुझाव पर आगे जा रहे हैं, मैं logging.Handler subclassed और हैंडलर एक निश्चित लंबाई के साथ collections.deque का उपयोग करता है लॉग संदेशों के रिकॉर्ड रखने के लिए लागू किया।

import logging 
import collections 


class TailLogHandler(logging.Handler): 

    def __init__(self, log_queue): 
     logging.Handler.__init__(self) 
     self.log_queue = log_queue 

    def emit(self, record): 
     self.log_queue.append(self.format(record)) 


class TailLogger(object): 

    def __init__(self, maxlen): 
     self._log_queue = collections.deque(maxlen=maxlen) 
     self._log_handler = TailLogHandler(self._log_queue) 

    def contents(self): 
     return '\n'.join(self._log_queue) 

    @property 
    def log_handler(self): 
     return self._log_handler 

उदाहरण उपयोग:

import random 

logger = logging.getLogger(__name__) 

tail = TailLogger(10) 

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 

log_handler = tail.log_handler 
log_handler.setFormatter(formatter) 
logger.addHandler(log_handler) 

levels = [logging.INFO, logging.ERROR, logging.WARN, logging.DEBUG, logging.CRITICAL] 
logger.setLevel(logging.ERROR) 

for i in range(500): 
    logger.log(random.choice(levels), 'Message {}'.format(i)) 

print(tail.contents()) 

आउटपुट:

2016-06-22 13:58:25,975 - __main__ - CRITICAL - Message 471 
2016-06-22 13:58:25,975 - __main__ - ERROR - Message 472 
2016-06-22 13:58:25,975 - __main__ - ERROR - Message 473 
2016-06-22 13:58:25,975 - __main__ - ERROR - Message 474 
2016-06-22 13:58:25,975 - __main__ - ERROR - Message 477 
2016-06-22 13:58:25,975 - __main__ - CRITICAL - Message 481 
2016-06-22 13:58:25,975 - __main__ - CRITICAL - Message 483 
2016-06-22 13:58:25,975 - __main__ - ERROR - Message 484 
2016-06-22 13:58:25,975 - __main__ - CRITICAL - Message 485 
2016-06-22 13:58:25,976 - __main__ - CRITICAL - Message 490 
6

Capturing Python Log Output In A Variable में वर्णित तकनीक का उपयोग करें, लेकिन इसे पुराने डेटा को फेंकने वाली कस्टम स्ट्रीम में कैप्चर करें।

तो जैसा:

# Adapted from http://alanwsmith.com/capturing-python-log-output-in-a-variable 

import logging 
import io 
import collections 

class FIFOIO(io.TextIOBase): 
    def __init__(self, size, *args): 
     self.maxsize = size 
     io.TextIOBase.__init__(self, *args) 
     self.deque = collections.deque() 
    def getvalue(self): 
     return ''.join(self.deque) 
    def write(self, x): 
     self.deque.append(x) 
     self.shrink() 
    def shrink(self): 
     if self.maxsize is None: 
      return 
     size = sum(len(x) for x in self.deque) 
     while size > self.maxsize: 
      x = self.deque.popleft() 
      size -= len(x) 

### Create the logger 
logger = logging.getLogger('basic_logger') 
logger.setLevel(logging.DEBUG) 

### Setup the console handler with a FIFOIO object 
log_capture_string = FIFOIO(256) 
ch = logging.StreamHandler(log_capture_string) 
ch.setLevel(logging.DEBUG) 

### Optionally add a formatter 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
ch.setFormatter(formatter) 

### Add the console handler to the logger 
logger.addHandler(ch) 


### Send log messages. 
logger.debug('debug message') 
logger.info('info message') 
logger.warn('warn message') 
logger.error('error message') 
logger.critical('critical message') 


### Pull the contents back into a string and close the stream 
log_contents = log_capture_string.getvalue() 
log_capture_string.close() 

### Output as lower case to prove it worked. 
print(log_contents.lower()) 
+0

आपके इनपुट के लिए धन्यवाद। इस कार्यान्वयन के साथ मेरी एकमात्र चिंता है (यह मूल पोस्ट में निर्दिष्ट नहीं थी), यह है कि [डॉक्स] (https://docs.python.org/3.5/library/io.html#multi-threading) स्थिति कि "TextIOWrapper ऑब्जेक्ट्स थ्रेड-सुरक्षित नहीं हैं", लेकिन वे 'TextIOBase' ऑब्जेक्ट्स के बारे में कुछ भी नहीं कहते हैं। साथ ही, वही [डॉक्स] (https://docs.python.org/3.5/library/io.html#id3) कहते हैं कि बड़ी फ़ाइलों से निपटने के दौरान 'स्ट्रिंगियो'' टेक्स्टियो 'से काफी तेज होना चाहिए। क्या आप 'टेक्स्टियोबेस' को 'स्ट्रिंगियो' के साथ अपने 'फीफोयो' बेस क्लास के रूप में बदल सकते हैं? –

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