become a logging expert in 30 minutes

Upload: yamabushi

Post on 02-Apr-2018

233 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    1/66

    Gavin M. Roy

    @crad

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    2/66

    Were Hiring!

    Senior Architects

    API Engineering Team

    Android

    iOS

    Web Front-End

    DevOps Engineers Network Engineers

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    3/66

    https://github.com/gmr/pycon2013-logging

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    4/66

    Why should you use logging?

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    5/66

    Common Pattern?try:ifdebug:print'Executingquery:%s'%query

    self.cursor.execute(query)exceptpsycopg2.OperationalError,e:

    sys.stderr.write('PostgreSQLError:%s'%e[0])sys.exit(1)exceptpsycopg2.IntegrityError,e:sys.stderr.write('PostgreSQLError:%r'%e[0])

    returnFalseexceptException,e:sys.stderr.write('UnhandledException:%r'%e[0])sys.exit(1)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    6/66

    Consistent Output Methodtry:logger.DEBUG('Executingquery:%s',query)cursor.execute(query)

    exceptpsycopg2.OperationalErroraserror:logger.CRITICAL('PostgreSQLException:%s',error)

    sys.exit(1)exceptpsycopg2.IntegrityErroraserror:

    logger.ERROR('PostgreSQLDataError:%s',error)returnFalse

    exceptExceptionasexception:logger.CRITICAL('UnhandledException:%s',exception)sys.exit(1)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    7/66

    Avoid NIH

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    8/66

    Configurable Destinations

    Files Rotating Files

    Logging

    EmailIn-Memory Buffer

    Syslog

    Console

    HTTP Web Service

    SocketTCP, UDP

    Windows NT Event Log

    Watched Files

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    9/66

    Configurable Formatting

    Standard string-

    formatting options

    Many attributes

    available

    Per destinationconditional formatting

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    10/66

    Filterable Content

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    11/66

    Easy to use API for:

    Debugging your application

    Providing runtime state information

    Triggering alerts upon specific

    conditions

    Sharing application data andinformation with external services

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    12/66

    Logging LevelsDEBUGINFO

    WARNING

    ERROR

    CRITICAL

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    13/66

    namespaces

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    14/66

    Using for writing Packages

    Common, well-documented methods

    and tools for configuration

    Users can control the level ofinformation they want/need

    Reduces the amount of code

    Ensure your package is more Pythonic

    and plays well with others

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    15/66

    The Logging Lexicon

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    16/66

    Log Records

    Used to build the logged messages,

    route them and filter them

    Hold all attributes about the message

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    17/66

    Loggers The logger is the first actor to

    decide if a message should be

    distributed to assignedhandlers

    Point of entry for all logged

    messages

    Provides destination fornamespaced logged

    messages

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    18/66

    The Object to Use

    debug(msg,*args,**kwargs)

    info(msg,*args,**kwargs)warning(msg,*args,**kwargs)

    error(msg,*args,**kwargs)

    exception(msg,*args)*

    * Logs at ERROR level and should be called only by exception handlers

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    19/66

    Root Logger

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    20/66

    propagate = True?

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    21/66

    foo.bar.baz

    when Propagate is True:

    apply to everything under foo

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    22/66

    Double Logging?

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    23/66

    incremental = True?

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    24/66

    Dangerous

    BehaviorIf loggers are alreadyconfigured, incremental=Truewill not change pre-existing

    configuration for formattersor filters

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    25/66

    Handlers

    Deliver messages to their destination

    Also filterable by level and filter

    Can have multiple per application

    Assigned to loggers

    Can have multiple per logger as well

    Assigned a formatter and any filters

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    26/66

    Formatters

    Use for destination specific formatting

    One formatter can be assigned to

    multiple handlers

    Responsible for merging internal values

    Uses Python %-style mapping keys to

    LogRecord attributes

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    27/66

    Example Formats%(levelname)s %(asctime)s %(module)s.%(funcName)s() (%(lineno)d): %(message)s

    INFO2013-03-1617:01:34web.log_request()(1462):200GET/(::1)0.41msINFO2013-03-1617:01:34web.log_request()(1462):200GET/(::1)0.33msINFO2013-03-1617:02:02web.log_request()(1462):200GET/(127.0.0.1)0.39msINFO2013-03-1617:02:03web.log_request()(1462):200GET/(127.0.0.1)0.27ms

    %(levelname)s %(name)s.%(funcName)s(): %(message)s

    root.log_request():200GET/(127.0.0.1)0.53msroot.log_request():200GET/(127.0.0.1)0.37msroot.log_request():200GET/(127.0.0.1)0.27msroot.log_request():200GET/(127.0.0.1)0.42ms

    http://web.log/http://web.log/http://web.log/http://web.log/http://web.log/http://web.log/
  • 7/27/2019 Become a Logging Expert in 30 Minutes

    28/66

    Log Adapters

    Build custom adapters

    to inject additional

    information not available

    to formatters by default

    Add context, simplify

    logger calls

    Same signature as a

    Logger, passed a loggeron construction

    Use like a Logger

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    29/66

    Filters

    Applied to Loggers

    Base class filters on namespace

    Example limiting logging to only items in

    the foo.bar.baznamespace:

    filter=logging.Filter('content')logger.addFilter(filter)

    Can be extended for your own purposes

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    30/66

    Configuration Options

    4 configuration options:

    Manually in code

    Very limiting, code change to alter

    configuration

    Dictionary based configuration (2.7+)

    File based configuration

    Socket listener configuration*

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    31/66

    DictConfig

    Allows for configuration to be passed in

    using a dict format

    Great for structured config data, such asconfiguration stored in JSON or YAML

    Can be very verbose

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    32/66

    DictConfig Example{'version': 1,

    'disable_existing_loggers': True,

    'incremental': False,

    'filters': [],

    'formatters': {'syslog': {'format': '%(levelname)s '

    '%(name)s.%(funcName)s(): %(message)s'},

    'verbose': {'datefmt': '%Y-%m-%d %H:%M:%S','format': '%(levelname) -10s %(asctime)s '

    '%(processName) -35s %(name) -35s '

    '%(funcName) -30s: %(message)s'}},

    'handlers': {'console': {'class': 'logging.StreamHandler',

    'debug_only': False,

    'formatter': 'verbose'},

    'syslog': {'address': '/var/run/syslog',

    'class': 'logging.handlers.SysLogHandler','facility': 'daemon',

    'formatter': 'syslog'}},

    'loggers': {'django': {'handlers': ['console', 'syslog'],

    'level': 'ERROR',

    'propagate': False},

    'psycopg2': {'handlers': ['console', 'syslog'],

    'level': 'INFO','propagate': True}}}

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    33/66

    DictConfig YAML ExampleLogging: formatters:

    brief:

    format: "%(levelname)s %(name)s.%

    (funcName)s(): %(message)s"

    filters: []

    handlers:

    console:class: logging.StreamHandler

    formatter: brief

    syslog:

    class: logging.handlers.SysLogHandler

    facility: daemon

    address: /dev/log

    formatter: brief loggers:

    django:

    propagate: true

    level: WARNING

    handlers: [console, syslog]

    psycopg2:

    propagate: false

    level: ERROR

    handlers: [console, syslog]

    disable_existing_loggers: true

    incremental: false

    version: 1

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    34/66

    Using a YAML config

    import logging.config

    import yaml

    config = yaml.load(open('config.yaml', 'r'))

    logging.config.dictConfig(config)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    35/66

    FileConfig

    ConfigParser formatted configuration

    files

    Cant use SafeConfigParser due toauto-string interpolation

    Somewhat more verbose than a YAML

    format

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    36/66

    FileConfig Example[loggers]keys=myapp[logger_myapp]level=INFOhandlers=syslog

    propagate=1qualname=myapp[handlers]keys=syslog[handler_syslog]class=handlers.SysLogHandler

    formatter=briefargs=('/dev/log',handlers.SysLogHandler.LOG_LOCAL6)[formatters]keys=brief[formatter_brief]format=%(name)s.%(funcName)s():%(message)s

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    37/66

    Logging Config Listener#!/usr/bin/envpythonimportlogging

    importlogging.configimporttime

    logging.basicConfig(level=logging.INFO)

    #Listenondefaultportof9030,isathread

    listener=logging.config.listen()listener.start()

    logger=logging.getLogger('listener')

    start_time=time.time()

    whileTrue:

    logger.info('Timesincestart:%.2f',time.time()-start_time)try:time.sleep(1)

    exceptKeyboardInterrupt:logging.config.stopListening()

    break

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    38/66

    Send to Listener

    #!/usr/bin/envpython

    importlogging.configimportsocket

    importstruct

    HOST='localhost'

    PORT=logging.config.DEFAULT_LOGGING_CONFIG_PORT#9030defsend_conf(config_text):s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    s.connect((HOST,PORT))s.send(struct.pack('>L',len(config_text)))s.send(config_text)

    s.close()

    withopen('logging.conf','r')ashandle:send_conf(handle.read())

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    39/66

    logger.cfg[loggers]keys=root,listener[logger_listener]level=INFOhandlers=consolepropagate=1qualname=listener

    [logger_root]level=WARNINGhandlers=console,syslogpropagate=1[handlers]keys=console,syslog[handler_console]class=StreamHandlerformatter=brief

    args=()stream=(ext://sys.stdout)[handler_syslog]class=handlers.SysLogHandlerformatter=briefargs=('/dev/log',handlers.SysLogHandler.LOG_LOCAL6)[formatters]keys=brief

    [formatter_brief]format=%(name)s.%(funcName)s():%(message)s

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    40/66

    OutputBeforecallingsend-config-to-listener.py

    INFO:listener:Timesincestart:0.00INFO:listener:Timesincestart:1.00

    INFO:listener:Timesincestart:2.00

    Aftercallingsend-config-to-listener.py

    listener.():Timesincestart:3.00listener.():Timesincestart:3.00

    listener.():Timesincestart:4.00listener.():Timesincestart:4.00

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    41/66

    stdlib Handlers

    StreamHandler

    FileHandler

    SyslogHandler

    WatchedFileHandler

    RotatingFileHandler

    TimedRotatingFileHandler

    NTEventLogHandler

    SocketHandler (TCP)

    DatagramHandler (UDP)

    SMTPHandler

    MemoryHandler

    HTTPHandler

    NullHandler

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    42/66

    Using SMTPHandler

    #!/usr/bin/envpython

    importloggingfromloggingimporthandlers

    importsocketimporttraceback

    HOST='localhost'FROM='"APPLICATIONALERT"'TO='you@your-domain'

    SUBJECT='NewCriticalEventFrom[APPLICATION]'

    logging.basicConfig(level=logging.INFO)handler=handlers.SMTPHandler(HOST,FROM,TO,SUBJECT)

    email_logger=logging.getLogger('smtp.example')

    email_logger.addHandler(handler)email_logger.setLevel=logging.CRITICAL

    logging.info('Rootloggeroutput')try:

    email_logger.critical('CriticalEventNotification\n\nTraceback:\n%s',''.join(traceback.format_stack()))

    exceptsocket.erroraserror:

    logging.critical('CouldnotsendemailviaSMTPHandler:%r',error)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    43/66

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    44/66

    Using HTTPHandler

    #!/usr/bin/envpython

    importloggingfromloggingimporthandlers

    importsocketimporttraceback

    HOST='localhost'PORT=8888

    logging.basicConfig(level=logging.INFO)

    handler=handlers.HTTPHandler('%s:%s'%(HOST,PORT),'/')http_logger=logging.getLogger('http.example')http_logger.addHandler(handler)

    http_logger.setLevel=logging.CRITICAL

    logging.info('Rootloggeroutput')try:

    http_logger.critical('CriticalEventNotification\n\nTraceback:\n%s',''.join(traceback.format_stack()))

    exceptsocket.erroraserror:logging.critical('CouldnotdelivermessageviaHTTPHandler:%r',error)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    45/66

    HTTPHandler Request Data{'args':'(\'File"http_handler-example.py",line21,in\\n''\\\'\\\'.join(traceback.format_stack()))\\n\',)',

    'created':'1363542183.32','exc_info':'None',

    'exc_text':'None','filename':'http_handler-example.py',

    'funcName':'',

    'levelname':'CRITICAL','levelno':'50','lineno':'21',

    'module':'http_handler-example','msecs':'316.456079483',

    'msg':'CriticalEventNotification\n\nTraceback:\n%s','name':'http.example',

    'pathname':'http_handler-example.py',

    'process':'13948','processName':'MainProcess','relativeCreated':'12.0251178741',

    'thread':'140735278571904','threadName':'MainThread'}

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    46/66

    Example Custom Handler

    Proof of concept application:

    Handler with a rotating log buffer

    Tornado web application to view log

    entries

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    47/66

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    48/66

    class WebRequestHandler(web.RequestHandler):

    def get(self):

    handler = self.application.log_handler

    self.write({'entries': handler.buffer})

    if self.get_argument('flush', False):

    handler.flush()

    Tornado Request Handler

    http://web.requesthandler/http://web.requesthandler/
  • 7/27/2019 Become a Logging Expert in 30 Minutes

    49/66

    if__name__== '__main__':

    logging.basicConfig(level=logging.INFO)

    routes=[(r'.*',WebRequestHandler)])

    application=web.Application(routes)

    application.listen(8888)

    application.log_handler=BufferedLogHandler(MAX)

    root_logger=logging.getLogger()

    root_logger.addHandler(application.log_handler)

    ioloop.IOLoop.instance().start()

    Setup & Start Application

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    50/66

    AMQPHandler?

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    51/66

    Logging

    Performance

    Fibonacci Sequence

    cProfile

    Python 2.7.2

    Python 3.3.0

    Default Handler

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    52/66

    Baseline Profile

    def fib(n):

    a, b = 0, 1

    while a < n:

    a, b = b, a+b

    fib(1000000)

    2.7 3.3

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    53/66

    import logging 2.7

    import logging

    def fib(n):

    a, b = 0, 1while a < n:

    a, b = b, a+b

    fib(1000000)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    54/66

    import logging 3.3

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    55/66

    level=INFO, debug 2.7import logging

    logger = logging.getLogger(__name__)

    logging.basicConfig(level=logging.INFO)

    def fib(n):

    a, b = 0, 1while a < n:

    logger.debug(Value: %i, a)

    a, b = b, a+b

    fib(1000000)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    56/66

    level=INFO, debug 3.3

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    57/66

    level=DEBUG, debug 2.7import logging

    logger = logging.getLogger(__name__)

    logging.basicConfig(level=logging.DEBUG)

    def fib(n):

    a, b = 0, 1while a < n:

    logger.debug(Value: %i, a)

    a, b = b, a+b

    fib(1000000)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    58/66

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    59/66

    Logging Performance

    0 ms

    0.375 ms

    0.75 ms

    1.125 ms

    1.5 ms

    import level=INFO level=DEBUG

    2.7 3.3

    * Chart data at end of deck on slide #62

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    60/66

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    61/66

    What to do?

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    62/66

    Use Debug*

    #*Butcheckifyourappisindebugmodefirstifdebug:

    LOGGER.debug('Hasstairsintheirhouse:%r',

    is_protected)

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    63/66

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    64/66

    https://github.com/gmr/pycon2013-logging

    Questions?

    Follow me on Twitter: @crad

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    65/66

  • 7/27/2019 Become a Logging Expert in 30 Minutes

    66/66

    Photo Credits

    Slide #12 "Back on the Log Train"Claire L. Evans

    http://www.flickr.com/photos/10097505@N00/1492818224/

    Slide #44 "I'm a lumberjack and I'm ok..."Neil Kremerhttp://www.flickr.com/photos/neilarmstrong2/