├── .idea
├── other.xml
└── testrunner.xml
├── config-examples
├── send-config-to-listener.py
├── logging-listener.py
├── logging.cfg
└── logging.yaml
├── http_handler-example.py
├── tornado-apps
├── http-handler-accept.py
└── buffered-log-handler.py
├── smtp-handler-example.py
└── svgs
├── fib-svg-no-logger.svg
├── fib-svg-no-logger-p3.svg
├── fib-svg-logging-p2.svg
├── fib-svg-logger-p2.svg
└── fib-svg-logger-debug-p2.svg
/.idea/other.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/testrunner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/config-examples/send-config-to-listener.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import logging.config
4 | import socket
5 | import struct
6 |
7 | HOST = 'localhost'
8 | PORT = logging.config.DEFAULT_LOGGING_CONFIG_PORT # 9030
9 |
10 |
11 | def send_conf(config_text):
12 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
13 | s.connect((HOST, PORT))
14 | s.send(struct.pack('>L', len(config_text)))
15 | s.send(config_text)
16 | s.close()
17 |
18 | with open('logging.cfg', 'r') as handle:
19 | send_conf(handle.read())
20 |
--------------------------------------------------------------------------------
/config-examples/logging-listener.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import logging
3 | import logging.config
4 | import time
5 |
6 | logging.basicConfig(level=logging.INFO)
7 |
8 | # Listen on default port of 9030, is a thread
9 | listener = logging.config.listen()
10 | listener.start()
11 |
12 | logger = logging.getLogger('listener')
13 |
14 | start_time = time.time()
15 | while True:
16 | logger.info('Time since start: %.2f', time.time() - start_time)
17 | try:
18 | time.sleep(1)
19 | except KeyboardInterrupt:
20 | logging.config.stopListening()
21 | break
22 |
--------------------------------------------------------------------------------
/config-examples/logging.cfg:
--------------------------------------------------------------------------------
1 | [loggers]
2 | keys = root, listener
3 |
4 | [logger_listener]
5 | level = INFO
6 | handlers = console
7 | propagate = 1
8 | qualname = listener
9 |
10 | [logger_root]
11 | level = WARNING
12 | handlers = console
13 | propagate = 1
14 |
15 | [handlers]
16 | keys = console, syslog
17 |
18 | [handler_console]
19 | class = StreamHandler
20 | formatter = brief
21 | stream = ext://sys.stdout
22 | args = ()
23 |
24 | [handler_syslog]
25 | class = handlers.SysLogHandler
26 | formatter = brief
27 | args = ('/var/run/syslog', handlers.SysLogHandler.LOG_LOCAL6)
28 |
29 | [formatters]
30 | keys = brief
31 |
32 | [formatter_brief]
33 | format = %(name)s.%(funcName)s(): %(message)s
34 |
--------------------------------------------------------------------------------
/http_handler-example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import logging
3 | from logging import handlers
4 | import socket
5 | import traceback
6 |
7 | HOST = 'localhost'
8 | PORT = 8888
9 |
10 | # Setup logging
11 | logging.basicConfig(level=logging.INFO)
12 |
13 | handler = handlers.HTTPHandler('%s:%s' % (HOST, PORT), '/')
14 | http_logger = logging.getLogger('http.example')
15 | http_logger.addHandler(handler)
16 | http_logger.setLevel = logging.CRITICAL
17 |
18 | logging.info('Root logger output')
19 | try:
20 | http_logger.critical('Critical Event Notification\n\nTraceback:\n %s',
21 | ''.join(traceback.format_stack()))
22 | except socket.error as error:
23 | logging.critical('Could not deliver message via HTTPHandler: %r', error)
24 |
--------------------------------------------------------------------------------
/tornado-apps/http-handler-accept.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import logging
3 | from tornado import ioloop, web
4 |
5 |
6 | class WebRequestHandler(web.RequestHandler):
7 | """Accepts HTTPHandler POSTs
8 |
9 | """
10 | def get(self):
11 | """Return a JSON document of the log entries and flush the
12 | BufferedLogHandler if there is a flush argument in the URL.
13 |
14 | """
15 | values = {k: ''.join(v) for k, v in self.request.arguments.iteritems()}
16 | logging.info('HTTPHandler data: %r', values)
17 | self.set_status(204)
18 |
19 | if __name__ == '__main__':
20 | logging.basicConfig(level=logging.INFO)
21 | routes = [(r'.*', WebRequestHandler)]
22 | application = web.Application(routes)
23 | application.listen(8888)
24 | ioloop.IOLoop.instance().start()
25 |
--------------------------------------------------------------------------------
/config-examples/logging.yaml:
--------------------------------------------------------------------------------
1 | Logging:
2 | formatters:
3 | brief:
4 | format: "%(levelname)s %(name)s.%(funcName)s(): %(message)s"
5 | filters: []
6 | handlers:
7 | console:
8 | class: logging.StreamHandler
9 | formatter: brief
10 | syslog:
11 | class: logging.handlers.SysLogHandler
12 | facility: daemon
13 | address: /dev/log
14 | formatter: brief
15 | loggers:
16 | django:
17 | propagate: true
18 | level: WARNING
19 | handlers: [console, syslog]
20 | psycopg2:
21 | propagate: false
22 | level: ERROR
23 | handlers: [console, syslog]
24 | ROOT:
25 | propagate: true
26 | level: WARNING
27 | handlers: [console, syslog]
28 | disable_existing_loggers: true
29 | incremental: false
30 | version: 1
31 |
--------------------------------------------------------------------------------
/smtp-handler-example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import logging
3 | from logging import handlers
4 | import socket
5 | import traceback
6 |
7 | HOST = 'localhost'
8 | FROM = '"APPLICATION ALERT" '
9 | TO = 'you@your-domain'
10 | SUBJECT = 'New Critical Event From [APPLICATION]'
11 |
12 | # Setup logging
13 | logging.basicConfig(level=logging.INFO)
14 |
15 | handler = handlers.SMTPHandler(HOST, FROM, TO, SUBJECT)
16 | email_logger = logging.getLogger('smtp.example')
17 | email_logger.addHandler(handler)
18 | email_logger.setLevel = logging.CRITICAL
19 |
20 | logging.info('Root logger output')
21 | try:
22 | email_logger.critical('Critical Event Notification\n\nTraceback:\n %s',
23 | ''.join(traceback.format_stack()))
24 | except socket.error as error:
25 | logging.critical('Could not send email via SMTPHandler: %r', error)
26 |
--------------------------------------------------------------------------------
/tornado-apps/buffered-log-handler.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from logging import handlers
3 | import logging
4 | from tornado import ioloop, web
5 |
6 | MAX_SIZE = 10485760 # 10 MB
7 |
8 |
9 | class BufferedLogHandler(handlers.BufferingHandler):
10 | """The BufferedLogHandler keeps a rolling buffer of log data in
11 | memory. When the buffer size has been exceeded, the oldest log
12 | entries will be removed.
13 |
14 | The max buffer size is passed into the constructor. See the
15 | logging.handlers.BufferingHandler for the full API.
16 |
17 | Access the log data as a list from the BufferedLogHandler.buffer
18 | attribute
19 |
20 | """
21 | def emit(self, record):
22 | """Append the formatted record to the buffer, removing oldest
23 | entries if the buffer size has passed the limit.
24 |
25 | :param logging.LogRecord record: The new record to log
26 |
27 | """
28 | self.buffer.append(self.format(record))
29 | while len(''.join(self.buffer)) >= self.capacity:
30 | self.buffer.remove(0)
31 |
32 |
33 | class WebRequestHandler(web.RequestHandler):
34 | """Tornado request handler that emits the BufferedLogHandler's
35 | buffer content in JSON format when GET was invoked. If flush
36 | is passed as a query value, the buffer will be flushed:
37 |
38 | /?flush=true
39 |
40 | """
41 | def get(self):
42 | """Return a JSON document of the log entries and flush the
43 | BufferedLogHandler if there is a flush argument in the URL.
44 |
45 | """
46 | handler = self.application.log_handler
47 | self.write({'log_entries': handler.buffer})
48 | if self.get_argument('flush', False):
49 | handler.flush()
50 |
51 |
52 | if __name__ == '__main__':
53 |
54 | # Setup logging
55 | logging.basicConfig(level=logging.INFO)
56 |
57 | # Create the web application
58 | routes = [(r'.*', WebRequestHandler)]
59 | application = web.Application(routes)
60 | application.listen(8888)
61 |
62 | # Create the log handler
63 | application.log_handler = BufferedLogHandler(MAX_SIZE)
64 |
65 | # Add the log handler to the root logger
66 | root_logger = logging.getLogger()
67 | root_logger.addHandler(application.log_handler)
68 |
69 | # Start the IOLoop
70 | ioloop.IOLoop.instance().start()
71 |
--------------------------------------------------------------------------------
/svgs/fib-svg-no-logger.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
44 |
--------------------------------------------------------------------------------
/svgs/fib-svg-no-logger-p3.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
52 |
--------------------------------------------------------------------------------
/svgs/fib-svg-logging-p2.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
247 |
--------------------------------------------------------------------------------
/svgs/fib-svg-logger-p2.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
367 |
--------------------------------------------------------------------------------
/svgs/fib-svg-logger-debug-p2.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
696 |
--------------------------------------------------------------------------------