1.. highlight:: shell
2.. _index:
3
4===================================
5`logzero`: Python logging made easy
6===================================
7
8Robust and effective logging for Python 2 and 3.
9
10.. image:: _static/demo-output-with-beaver.png
11   :alt: Logo
12
13**Features**
14
15* Easy logging to console and/or (rotating) file.
16* Provides a fully configured `Python logger object <https://docs.python.org/2/library/logging.html#module-level-functions>`_.
17* Pretty formatting, including level-specific colors in the console.
18* JSON logging support (with integrated `python-json-logger <https://github.com/madzak/python-json-logger>`_)
19* Windows color output supported by `colorama`_
20* Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters.
21* Multiple loggers can write to the same logfile (also works across multiple Python files).
22* Global default logger with `logzero.logger <#i-logzero-logger>`_ and custom loggers with `logzero.setup_logger(..) <#i-logzero-setup-logger>`_.
23* Compatible with Python 2 and 3.
24* All contained in a `single file`_.
25* Licensed under the MIT license.
26* Heavily inspired by the `Tornado web framework`_.
27* Hosted on GitHub: https://github.com/metachris/logzero
28
29
30Installation
31============
32
33Install `logzero` with `pip`_:
34
35.. code-block:: console
36
37    $ pip install -U logzero
38
39If you don't have `pip`_ installed, this `Python installation guide`_ can guide
40you through the process.
41
42You can also install `logzero` from the public `Github repo`_:
43
44.. code-block:: console
45
46    $ git clone https://github.com/metachris/logzero.git
47    $ cd logzero
48    $ python setup.py install
49
50.. _pip: https://pip.pypa.io
51.. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/
52.. _Github repo: https://github.com/metachris/logzero
53.. _tarball: https://github.com/metachris/logzero/tarball/master
54.. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py
55.. _Tornado web framework: https://github.com/tornadoweb/tornado
56.. _colorama: https://github.com/tartley/colorama
57
58
59Example usage
60=============
61
62You can use `logzero` like this (logs only to the console by default):
63
64.. code-block:: python
65
66    from logzero import logger
67
68    logger.debug("hello")
69    logger.info("info")
70    logger.warning("warn")
71    logger.error("error")
72
73    # This is how you'd log an exception
74    try:
75        raise Exception("this is a demo exception")
76    except Exception as e:
77        logger.exception(e)
78
79    # JSON logging
80    import logzero
81    logzero.json()
82
83    logger.info("JSON test")
84
85    # Start writing into a logfile
86    logzero.logfile("/tmp/logzero-demo.log")
87
88If this was a file called ``demo.py``, the output will look like this:
89
90.. image:: _static/demo-output-json.png
91   :alt: Demo output in color
92
93Logging to files
94----------------
95
96You can add logging to a (rotating) logfile like this:
97
98.. code-block:: python
99
100    import logzero
101    from logzero import logger
102
103    # non-rotating logfile
104    logzero.logfile("/tmp/logfile.log")
105
106    # rotating logfile
107    logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1e6, backupCount=3)
108
109    # log messages
110    logger.info("This log message goes to the console and the logfile")
111
112
113JSON logging
114------------
115
116JSON logging can be enabled for the default logger with `logzero.json()`, or with `setup_logger(json=True)` for custom loggers:
117
118.. code-block:: python
119
120    # Configure the default logger to output JSON
121    >>> logzero.json()
122    >>> logger.info("test")
123    {"asctime": "2020-10-21 10:42:45,808", "filename": "<stdin>", "funcName": "<module>", "levelname": "INFO", "levelno": 20, "lineno": 1, "module": "<stdin>", "message": "test", "name": "logzero_default", "pathname": "<stdin>", "process": 76179, "processName": "MainProcess", "threadName": "MainThread"}
124
125    # Configure a custom logger to output JSON
126    >>> my_logger = setup_logger(json=True)
127    >>> my_logger.info("test")
128    {"asctime": "2020-10-21 10:42:45,808", "filename": "<stdin>", "funcName": "<module>", "levelname": "INFO", "levelno": 20, "lineno": 1, "module": "<stdin>", "message": "test", "name": "logzero_default", "pathname": "<stdin>", "process": 76179, "processName": "MainProcess", "threadName": "MainThread"}
129
130The logged JSON object has these fields:
131
132.. code-block:: json
133
134    {
135        "asctime": "2020-10-21 10:43:40,765",
136        "filename": "test.py",
137        "funcName": "test_this",
138        "levelname": "INFO",
139        "levelno": 20,
140        "lineno": 9,
141        "module": "test",
142        "message": "info",
143        "name": "logzero",
144        "pathname": "_tests/test.py",
145        "process": 76204,
146        "processName": "MainProcess",
147        "threadName": "MainThread"
148    }
149
150An exception logged with `logger.exception(e)` has these:
151
152.. code-block:: json
153
154    {
155        "asctime": "2020-10-21 10:43:25,193",
156        "filename": "test.py",
157        "funcName": "test_this",
158        "levelname": "ERROR",
159        "levelno": 40,
160        "lineno": 17,
161        "module": "test",
162        "message": "this is a demo exception",
163        "name": "logzero",
164        "pathname": "_tests/test.py",
165        "process": 76192,
166        "processName": "MainProcess",
167        "threadName": "MainThread",
168        "exc_info": "Traceback (most recent call last):\n  File \"_tests/test.py\", line 15, in test_this\n    raise Exception(\"this is a demo exception\")\nException: this is a demo exception"
169    }
170
171
172Advanced usage examples
173-----------------------
174
175Here are more examples which show how to use logfiles, custom formatters
176and setting a minimum loglevel.
177
178+-----------------------------------------+--------------------------------------------------+
179| Outcome                                 | Method                                           |
180+=========================================+==================================================+
181| Set a minimum log level                 | `logzero.loglevel(..) <#i-logzero-loglevel>`_    |
182+-----------------------------------------+--------------------------------------------------+
183| Add logging to a logfile                | `logzero.logfile(..) <#i-logzero-logfile>`_      |
184+-----------------------------------------+--------------------------------------------------+
185| Setup a rotating logfile                | `logzero.logfile(..) <#i-logzero-logfile>`_      |
186+-----------------------------------------+--------------------------------------------------+
187| Disable logging to a logfile            | `logzero.logfile(None) <#i-logzero-logfile>`_    |
188+-----------------------------------------+--------------------------------------------------+
189| JSON logging                            | `logzero.json(...) <#json-logging>`_             |
190+-----------------------------------------+--------------------------------------------------+
191| Log to syslog                           | `logzero.syslog(...) <#i-logzero-logfile>`_      |
192+-----------------------------------------+--------------------------------------------------+
193| Use a custom formatter                  | `logzero.formatter(..) <#i-logzero-formatter>`_  |
194+-----------------------------------------+--------------------------------------------------+
195
196
197.. code-block:: python
198
199    import logging
200    import logzero
201    from logzero import logger
202
203    # This log message goes to the console
204    logger.debug("hello")
205
206    # Set a minimum log level
207    logzero.loglevel(logzero.INFO)
208
209    # Set a logfile (all future log messages are also saved there)
210    logzero.logfile("/tmp/logfile.log")
211
212    # Set a logfile (all future log messages are also saved there), but disable the default stderr logging
213    logzero.logfile("/tmp/logfile.log", disableStderrLogger=True)
214
215    # You can also set a different loglevel for the file handler
216    logzero.logfile("/tmp/logfile.log", loglevel=logzero.ERROR)
217
218    # Set a rotating logfile (replaces the previous logfile handler)
219    logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3)
220
221    # Disable logging to a file
222    logzero.logfile(None)
223
224    # Enable JSON log format
225    logzero.json()
226
227    # Disable JSON log format
228    logzero.json(False)
229
230    # Log to syslog, using default logzero logger and 'user' syslog facility
231    logzero.syslog()
232
233    # Log to syslog, using default logzero logger and 'local0' syslog facility
234    logzero.syslog(facility=SysLogHandler.LOG_LOCAL0)
235
236    # Set a custom formatter
237    formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s');
238    logzero.formatter(formatter)
239
240    # Log some variables
241    logger.info("var1: %s, var2: %s", var1, var2)
242
243Custom logger instances
244-----------------------
245
246Instead of using the default logger you can also setup specific logger instances with `logzero.setup_logger(..) <#i-logzero-setup-logger>`_:
247
248.. code-block:: python
249
250    from logzero import setup_logger
251    logger1 = setup_logger(name="mylogger1")
252    logger2 = setup_logger(name="mylogger2", logfile="/tmp/test-logger2.log", level=logzero.INFO)
253    logger3 = setup_logger(name="mylogger3", logfile="/tmp/test-logger3.log", level=logzero.INFO, disableStderrLogger=True)
254
255    # Log something:
256    logger1.info("info for logger 1")
257    logger2.info("info for logger 2")
258
259    # log to a file only, excluding the default stderr logger
260    logger3.info("info for logger 3")
261
262    # JSON logging in a custom logger
263    jsonLogger = setup_logger(name="jsonLogger", json=True)
264    jsonLogger.info("info in json")
265
266
267
268Adding custom handlers (eg. SocketHandler)
269------------------------------------------
270
271Since `logzero` uses the standard `Python logger object <https://docs.python.org/2/library/logging.html#module-level-functions>`_,
272you can attach any `Python logging handlers <https://docs.python.org/2/library/logging.handlers.html>`_ you can imagine!
273
274This is how you add a `SocketHandler <https://docs.python.org/2/library/logging.handlers.html#sockethandler>`_:
275
276.. code-block:: python
277
278    import logzero
279    import logging
280    from logging.handlers import SocketHandler
281
282    # Setup the SocketHandler
283    socket_handler = SocketHandler(address=('localhost', logging.DEFAULT_TCP_LOGGING_PORT))
284    socket_handler.setLevel(logging.DEBUG)
285    socket_handler.setFormatter(logzero.LogFormatter(color=False))
286
287    # Attach it to the logzero default logger
288    logzero.logger.addHandler(socket_handler)
289
290    # Log messages
291    logzero.logger.info("this is a test")
292
293
294Documentation
295=============
296
297.. _i-logzero-logger:
298
299`logzero.logger`
300----------------
301
302`logzero.logger` is an already set up standard `Python logger instance <https://docs.python.org/2/library/logging.html#module-level-functions>`_ for your convenience. You can use it from all your
303files and modules directly like this:
304
305.. code-block:: python
306
307    from logzero import logger
308
309    logger.debug("hello")
310    logger.info("info")
311    logger.warning("warning")
312    logger.error("error")
313
314You can reconfigure the default logger globally with `logzero.setup_default_logger(..) <#i-logzero-setup-default-logger>`_.
315
316See the documentation for the `Python logger instance <https://docs.python.org/2/library/logging.html#module-level-functions>`_ for more information about how you can use it.
317
318
319.. _i-logzero-loglevel:
320
321`logzero.loglevel(..)`
322--------------------------
323
324.. autofunction:: logzero.loglevel
325
326
327.. _i-logzero-logfile:
328
329`logzero.logfile(..)`
330--------------------------
331
332.. autofunction:: logzero.logfile
333
334
335.. _i-logzero-formatter:
336
337`logzero.formatter(..)`
338--------------------------
339
340.. autofunction:: logzero.formatter
341
342
343.. _i-logzero-setup-logger:
344
345`logzero.setup_logger(..)`
346--------------------------
347
348.. autofunction:: logzero.setup_logger
349
350.. _i-logzero-setup-default-logger:
351
352
353Default Log Format
354------------------
355
356This is the default log format string:
357
358.. code-block:: python
359
360    DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'
361
362See also the `Python LogRecord attributes <https://docs.python.org/2/library/logging.html#logrecord-attributes>`_ you can use.
363
364
365Custom Formatting
366-----------------
367
368It is easy to use a custom formatter / a custom log format string:
369
370* Define your log format string (you can use any of the `LogRecord attributes <https://docs.python.org/2/library/logging.html#logrecord-attributes>`_).
371* Create a `Formatter object <https://docs.python.org/2/library/logging.html#formatter-objects>`_ (based on `logzero.LogFormatter` to get all the encoding helpers).
372* Supply the formatter object to the `formatter` argument in the `setup_logger(..)` method.
373
374This is a working example on how to setup logging with a custom format:
375
376.. code-block:: python
377
378    import logzero
379
380    log_format = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'
381    formatter = logzero.LogFormatter(fmt=log_format)
382    logzero.setup_default_logger(formatter=formatter)
383
384
385Issues, Feedback & Contributions
386================================
387
388All kinds of feedback and contributions are welcome.
389
390* `Create an issue <https://github.com/metachris/logzero/issues/new>`_
391* Create a pull request
392* https://github.com/metachris/logzero
393* chris@linuxuser.at // `@metachris <https://twitter.com/metachris>`_
394