Python logs, support for color printing and file size slices writing and writing to MongoDB

Source: Internet
Author: User
Tags emit mongodb collection



A log that supports different logger name writes to different files, different logger name logs are written to different MongoDB collection. Logmanager is easier to call, because the internal methods are all using underscores, the use of the underscore is that the protection and private methods do not need to call the outside world, do not need to understand him, at the time of the call Pycharm will not automatically complete the hint of these underlined irrelevant method, only exposed get_ And_add_handlers and Get_without_handlers two methods that may need to be called, Pyrcharm can automatically complement the two methods.






The main ideas and patterns are:



Logger add handler, each write Logger.debug/info support log a variety of records, because logger and handler is Publisher and subscriber relationship, in design mode is called Observer mode. When Logger.debug is in progress, logger calls its own _log method, _log method calls the handle method, handle calls the call handler method, Callhandler finds all subscribers, The handle method that invokes the Subscriber (the subscriber here is a variety of handler objects that have been added to the list by AddHandler), and the handler method of handler calls the Emit method. So you only need to inherit logging when writing custom handler. Handler class, overriding the emit method is possible. If you have special needs to pass in other parameters, you will need to override the Init method in addition to the emit method.



So a total of two main design patterns in the inside, logger and various handler objects with the pattern is the observer pattern, various patterns of the handler class and the basic handler class is the use of template mode (template mode is the main method of the steps in the base class write, Some of the different steps in the template class are set for abstract methods, and subclasses must be overridden. )


# coding = utf8

"" "

Log management, support log printing to the console or writing to a file or mongodb

Use it as logger = LogManager (‘logger_name’). Get_and_add_handlers (log_level_int = 1, is_add_stream_handler = True, log_path = None, log_filename = None, log_file_size = 10, mongo_url = None, formatter_template = 2)

Or logger = LogManager (‘logger_name’). Get_without_handlers (), this kind of logs are not recorded immediately, after that, all logs can be captured and recorded by get_and_add_handlers according to loggerame at a single unified main gate.

"" "

import os

import unittest

import time

import re

from collections import OrderedDict

import pymongo

import logging

from logging.handlers import RotatingFileHandler


if os.name == ‘posix’:

   from cloghandler import ConcurrentRotatingFileHandler


formatter_dict = {

   1: logging.Formatter ('log time [% (asctime) s]-log name [% (name) s]-file [% (filename) s]-line [% (lineno) d]-log level [% (levelname) s]-log message [% (message) s] ', "% Y-% m-% d% H:% M:% S"),

   2: logging.Formatter ('% (asctime) s-% (name) s-% (filename) s-% (lineno) d-% (levelname) s-% (message) s', "% Y-% m -% d% H:% M:% S "),

}



class LogLevelException (Exception):

   def __init __ (self, log_level):

       err = ‘the set log level is {0}, the setting is wrong, please set it to a number in the range 1 2 3 4 5’.format (log_level)

       Exception .__ init __ (self, err)



class MongoHandler (logging.Handler):

   "" "

   A mongodb log handler that supports creating different collections by loggername and writing to mongodb

   "" "

   msg_pattern = re.compile ('(\ d +-\ d +-\ d + \ d +: \ d +: \ d +)-(\ S *?)-(\ S *?)-(\ d +)-(\ S *? )-([\ s \ S] *) ')


   def __init __ (self, mongo_url, mongo_database = ‘logs’):

       "" "

       : param mongo_url: mongo connection

       : param mongo_database: save the log ide database, the logs database is used by default

       "" "

       logging.Handler .__ init __ (self)

       mongo_client = pymongo.MongoClient (mongo_url)

       self.mongo_db = mongo_client.get_database (mongo_database)


   def emit (self, record):

       try:

           "" "The following method is used to extract the field" "

           # msg = self.format (record)

           # logging.LogRecord

           # msg_match = self.msg_pattern.search (msg)

           # log_info_dict = {‘time’: msg_match.group (1),

           # ‘Name’: msg_match.group (2),

           # ‘File_name’: msg_match.group (3),

           # ‘Line_no’: msg_match.group (4),

           # ‘Log_level’: msg_match.group (5),

           # ‘Detail_msg’: msg_match.group (6),

           #}

           level_str = None

           if record.levelno == 10:

               level_str = ‘DEBUG’

           elif record.levelno == 20:

               level_str = ‘INFO’

           elif record.levelno == 30:

               level_str = ‘WARNING’

           elif record.levelno == 40:

               level_str = ‘ERROR’

           elif record.levelno == 50:

               level_str = ‘CRITICAL’

           log_info_dict = OrderedDict ()

           log_info_dict [‘time’] = time.strftime (‘% Y-% m-% d% H:% M:% S’)

           log_info_dict [‘name’] = record.name

           log_info_dict [‘file_path’] = record.pathname

           log_info_dict [‘file_name’] = record.filename

           log_info_dict [‘func_name’] = record.funcName

           log_info_dict [‘line_no’] = record.lineno

           log_info_dict [‘log_level’] = level_str

           log_info_dict [‘detail_msg’] = record.msg

           col = self.mongo_db.get_collection (record.name)

           col.insert_one (log_info_dict)

       except (KeyboardInterrupt, SystemExit):

           raise

       except:

           self.handleError (record)



class ColorHandler (logging.StreamHandler):

   "" "Color log, showing different colors according to different levels of log" ""


   def emit (self, record):

       "" "

       0 40 black

       31 41 red

       32 42 green

       33 43 yellow

       34 44 blue

       35 45 fuchsia

       36 46 cyan

       37 47 white

       : param record:

       : return:

       "" "

       try:

           # logging.LogRecord.levelno

           msg = self.format (record)


           if record.levelno == 10:

               print (‘\ 033 [0; 32m% s \ 033 [0m’% msg) # green

           elif record.levelno == 20:

               print (‘\ 033 [0; 36m% s \ 033 [0m’% msg) # cyan

           elif record.levelno == 30:

               print (‘\ 033 [0; 34m% s \ 033 [0m’% msg) # blue

           elif record.levelno == 40:

               print (‘\ 033 [0; 35m% s \ 033 [0m’% msg) # fuchsia

           elif record.levelno == 50:

               print (‘\ 033 [0; 31m% s \ 033 [0m’% msg) # blood red

       except (KeyboardInterrupt, SystemExit):

           raise

       except:

           self.handleError (record)



class LogManager (object):

   "" "

   A log class for creating and capturing logs, supporting printing to the console, printing, and writing to log files.

   "" "


   def __init __ (self, logger_name = None):

       "" "

       : param logger_name: log name, print all logs when None

       "" "

       self.logger = logging.getLogger (logger_name)

       self._logger_level = None

       self._is_add_stream_handler = None

       self._log_path = None

       self._log_filename = None

       self._log_file_size = None

       self._mongo_url = None

       self._formatter = None


   def get_logger_and_add_handlers (self, log_level_intg ‘)

       LogManager (‘test’). Get_logger_and_add_handlers (1, log_path = ‘.. / logs’, log_filename = ‘test.log’)

       test_log = LogManager (‘test’). get_logger_and_add_handlers (1, log_path = ‘.. / logs’, log_filename = ‘test.log’)

       print (‘The following sentence does not repeat printing four times and write to the log four times’)

       time.sleep (1)

       test_log.debug (‘this sentence will not be printed four times and written to the log four times’)


   @ unittest.skip

   def test_get_logger_without_hanlders (self):

       "" "Testing logs without handlers" ""

       log = LogManager (‘test2’). get_logger_without_handlers ()

       print ('The following sentence will not be printed')

       time.sleep (1)

       log.info (‘this sentence will not be printed’)


   @ unittest.skip

   def test_add_handlers (self):

       "" "This allows you to write debug and info level logs at any specific place. You only need to specify the level at the main gate to filter, which is very convenient.

       LogManager (‘test3’). Get_logger_and_add_handlers (2)

       log1 = LogManager (‘test3’). get_logger_without_handlers ()

       print (‘The following sentence is info level and can be printed’)

       time.sleep (1)

       log1.info (‘This sentence is info level and can be printed’)

       print (‘The following sentence is a debug level and cannot be printed’)

       time.sleep (1)

       log1.debug (‘This sentence is a debug level and cannot be printed’)


   @ unittest.skip

   def test_only_write_log_to_file (self):

       "" "Write to log file only" ""

       log5 = LogManager (‘test5’). get_logger_and_add_handlers (is_add_stream_handler = False, log_path = ‘.. / logs’, log_filename = ‘test5.log’)

       print ('The following sentence is only written to the file')

       log5.debug ('This sentence is only written to the file')


   def test_color_and_mongo_hanlder (self):

       "" "Testing colored logs and log writing to mongodb" ""

       from app import config

       logger = LogManager (‘helloMongo’). get_logger_and_add_handlers (mongo_url = config.connect_url)

       logger.debug ('a debug-level log')

       logger.info ('an info-level log')

       logger.warning (‘a warning level’ ’)

       logger.error (‘an error-level log’)

       logger.critical (‘A critical level log’)



if __name__ == "__main__":

   unittest.main ()








The effect of Test_color_and_mongo_hanlder is as follows.

Because the custom Colorhandler is added to logger, the log recorded by the console is colored.



MongoDB inside









Using the Name property of the log logger as the name of the collection, different Loggername create different collection. The main saved field has the journal name, which is the level of log and log details in what file of what function/method is printed.






Python logs, support for color printing and file size slices writing and writing to MongoDB


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.