{ "info": { "author": "Bitpanda GmbH", "author_email": "nosupport@bitpanda.com", "bugtrack_url": null, "classifiers": [ "Topic :: Utilities" ], "description": "[![Build Status](https://travis-ci.org/bitpanda-labs/loggo.svg?branch=master)](https://travis-ci.org/bitpanda-labs/loggo)\n[![codecov.io](https://codecov.io/gh/bitpanda-labs/loggo/branch/master/graph/badge.svg)](https://codecov.io/gh/bitpanda-labs/loggo)\n[![PyPI version](https://badge.fury.io/py/loggo.svg)](https://badge.fury.io/py/loggo)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)\n\n# `@loggo`: automated logging for Python 3\n\n\n> Version 6.0.1\n\n> You find Python's builtin `logging` module repetitive, tedious and ugly, and the logs you do write with it clash with your otherwise awesome style. `loggo` is here to help: it automates the boring stuff, simplifies the tricky stuff, hooks up effortlessly to [graylog](https://www.graylog.org/), and keeps an eye out for privacy and security if you need it to.\n\n## Install\n\n```\npip install loggo\n# or\npython setup.py install\n```\n\n## Setup\n\nTo get started, import and instantiate the main class, ideally somewhere at the core of your project. If you have a module with multiple files, do the initial configuration in the main `__init__.py`, or in a file called `log.py`. so you can import the same, ready-set-up logger easily.\n\nFor example, if your app was called `tester`, you could add the following to `tester/__init__.py`:\n\n```python\nfrom loggo import Loggo\n\n# all setup values are optional\nloggo = Loggo(\n facility=\"tester\", # name of program logging the message\n graylog_address=(\"0.0.0.0\", 9999), # address for graylog (ip, port)\n do_print=True, # print each log to console\n do_write=True, # write each log to file\n logfile=\"mylog.txt\", # custom path to logfile\n truncation=1000, # longest possible value in extra data\n private_data={\"password\"}, # set of sensitive args/kwargs\n)\n```\n\n## Usage\n\nIn other parts of the project, you can then access the configured logger instance with:\n\n```python\nfrom tester import loggo\n```\n\n### Loggo as decorator\n\nYou can use `@loggo` as a decorator on any callable: a class, on its method, or on function. On classes, it will log every method; on methods and functions it will log the call signature, return and errors. The central idea behind `loggo` is that you can simply decorate every class in your project, as well as any important standalone functions, and have comprehensive, standardised information about your project's internals without any extra labour.\n\nIf a method within a decorated class is called too often, or if you don't need to keep an eye on it, you can use `@loggo.ignore` to ignore it. Also available is `@loggo.errors`, which will only log exceptions, not calls and returns.\n\nFor an example use-case, let's make a simple class that multiplies two numbers, but only if a password is supplied. We will ignore logging of the boring authentication system.\n\n```python\n@loggo\nclass Multiplier:\n def __init__(self, base):\n self.base = base\n\n def multiply(self, n, password):\n \"\"\"\n Multiply by the number given during initialisation--requires password\n \"\"\"\n self.authenticated = self._do_authentication(password)\n if not self.authenticated:\n raise ValueError(\"Not authenticated!\")\n return self.base * n\n\n @loggo.ignore\n def _do_authentication(self, password):\n \"\"\"Not exactly Fort Knox\"\"\"\n return password == \"tOpSeCrEt\"\n```\n\nFirst, let's use it properly, with our secret password passed in:\n\n```python\nmult = Multiplier(50)\nresult = mult.multiply(50, \"tOpSeCrEt\")\nassert result == 2500 # True\n```\n\nWe'll get some nice text in the console:\n\n```\n11.05 2018 17:14:54 *Called Multiplier.multiply(n=50, password='******')\n11.05 2018 17:14:54 *Returned from Multiplier.multiply(n=50, password='******') with int (2500)\n```\n\nNotice that our private argument `password` was successfully obscured, even without us naming the argument when we called the method. If you used `do_write=True`, this log will also be in your specified log file, also with password obscured.\n\n```python\nresult = mult.multiply(7, \"password123\")\n```\n\nHere an error will raise, a log will be generated, and we'll get extra info in the console, including traceback:\n\n```\n11.05 2018 17:19:43 *Called Multiplier.multiply(n=7, password='******')\n11.05 2018 17:19:43 *Errored during Multiplier.multiply(n=7, password='******') with ValueError \"Not authenticated!\" 20 -- see below:\nTraceback (most recent call last):\n File \"/Users/danny/work/loggo/loggo/loggo.py\", line 137, in full_decoration\n response = function(*args, **kwargs)\n File \"tester.py\", line 13, in multiply\n raise ValueError('Not authenticated!')\nValueError: Not authenticated!\n```\n\nIf you're using [graypy](https://github.com/severb/graypy/), you'll get a lot of extra goodness, such as key-value pairs for call signatures, timestamps, arguments, return values, exception information, and so on.\n\n### Custom messages\n\nWhen configuring `loggo`, you can use your own message format for the auto-generated logs. There are four keys, one for each autolog type:\n\n```python\nloggo = Loggo(\n called=\"Log before callable is run\",\n returned=\"Log for return from {call_signature} at {timestamp}\",\n returned_none=\"Log when the return value of the callable is None\",\n errored=\"Log string on exception: {exception_type}\",\n)\n\n\n@loggo\ndef test():\n pass\n```\n\nIf you pass `None` for any of these keyword arguments, logs of that time will be completely suppressed. If you do not provide a value for `returned_none`, `loggo` will use the value you provided for `returned`, or fall back to its own default.\n\nNotice, in the example above, you can include particular format strings in the log message. Currently supported are:\n* `call_signature`: the callable name and its arguments and keyword arguments\n* `callable`: the `__qualname__` of the decorated object\n* `params`: comma separated key value pairs for arguments passed\n* `log_level`: the log level associated with this log\n* `timestamp`: time at time of logging\n* `couplet`: `uuid.uuid1()` for the called and returned/errored pair\n* `number_of_params`: total `args + kwargs` as int\n* `private_keys`: list of identified private argument names\n* `decorated`: always `True`\n\nThe `errored` log additionally supports:\n* `exception_type`: `ValueError`, `AttributeError`, etc.\n* `exception_msg`: details about the thrown exception\n* `traceback`: exception traceback\n\nAnd the `returned` and `returned_none` logs support:\n* `return_value`: the object returned by the callable\n* `return_type`: type of returned object\n\nAdding more such strings is trivial; submit an issue if there is something else you need.\n\n### Logging without decorators\n\nFor logging manually, `loggo` provides methods similar to the logging functions of the `logging` standard library: `loggo.log`, `loggo.debug`, `loggo.info`, `loggo.warning`, `loggo.error`, and `loggo.critical`. The methods use the configuration that has already been defined. The main method `loggo.log` takes three parameters:\n\n```python\nlevel = 50\nmsg = \"Message to log\"\nextra = dict(some=\"data\", that=\"will\", be=\"logged\")\nloggo.log(level, msg, extra)\n# console: 11.05 2018 17:36:24 Message to log 50\n# extra_data in log file if `do_print` setting is True\n```\n\nMethods `loggo.debug`, `loggo.info`, `loggo.warning`, `loggo.error` and `loggo.critical` are convenience methods for setting the log level. For instance,\n\n```python\nloggo.warning(\"A message\", dict(some=\"data\"))\n```\n\nis equivalent to\n\n```python\nloggo.log(logging.WARNING, \"A message\", dict(some=\"data\"))\n```\n\nwhere `logging.WARNING` is an integer constant imported from the standard library.\n\nThe advantage of using `loggo` for these kinds of logs is that `loggo` will make the extra data more readable and truncate very large strings. More importantly, you also still get whatever extras you've configured, like obfuscation of private data, or writing to console/file.\n\n### Methods\n\nYou can also start and stop logging with `loggo.start()` and `loggo.stop()`, at any point in your code, though by default, error logs will still get through. If you want to suppress errors too, you can pass in `allow_errors=False`.\n\n### Context managers\n\nYou can suppress logs using a context manager. Errors are allowed here by default too:\n\n```python\nwith loggo.pause(allow_errors=False):\n do_something()\n```\n\n## Contributing\n\n### Style\nThe style is [Black](https://github.com/python/black), with the following exceptions and extra strictness:\n* Maximum line length is 110\n* The comment syntax for types should not be used unless ignoring with `# type: ignore`. That is, write this:\n ```python\n def hello() -> str:\n return_value: str = 'hello'\n return return_value\n ```\n instead of writing this:\n ```python\n def hello(): # type: () -> str\n return_value = 'hello' # type: str\n return return_value\n ```\n\n### Making pull requests\n\nIssues, feature requests and code contributions are welcomed. Follow these steps to make a pull request:\n\n1. Fork/clone the repository.\n\n1. Install dependencies (you'll probably want to create a virtual environment, using your preferred method, first).\n ```bash\n pip install -r requirements.txt\n ```\n\n1. Install pre-commit hooks\n ```bash\n pre-commit install\n ```\n\n1. After making changes and having written tests, make sure tests pass:\n ```bash\n python -m unittest\n ```\n\n1. Commit, push, and make a PR.\n\n\n### Version bumping\n\n`loggo` adheres to semantic versioning, ideally via the `bump2version` utility. Install it with pip:\n\n```bash\npip install bump2version\n```\n\nWhenever you need to bump version, in the project root directory do:\n\n```bash\nbump2version (major | minor | patch)\ngit push --follow-tags \n```\n\n## Limitations\n\n`loggo` uses Python's standard library (`logging`) to generate logs. There are some gotchas when using it: for instance, in terms of the extra data that can be passed in, key names for this extra data cannot clash with some internal names used within the `logging` module (`message`, `args`, etc.). To get around this, you'll get a warning that your data contains a bad key name, and it will be changed (i.e. from `message` to `protected_message`).", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/bitpanda-labs/loggo", "keywords": "bitpanda utilities", "license": "", "maintainer": "", "maintainer_email": "", "name": "loggo", "package_url": "https://pypi.org/project/loggo/", "platform": "", "project_url": "https://pypi.org/project/loggo/", "project_urls": { "Homepage": "https://github.com/bitpanda-labs/loggo" }, "release_url": "https://pypi.org/project/loggo/6.0.1/", "requires_dist": null, "requires_python": ">=3.6", "summary": "Python logging tools", "version": "6.0.1" }, "last_serial": 5523617, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "abc588aa78da3609426753b04be5a5c1", "sha256": "e9b6eaa72a7cc32f215f9f1b1e95556f33072990091413f002736572b4ff1596" }, "downloads": -1, "filename": "loggo-0.0.1-py3.6.egg", "has_sig": false, "md5_digest": "abc588aa78da3609426753b04be5a5c1", "packagetype": "bdist_egg", "python_version": "3.6", "requires_python": null, "size": 20138, "upload_time": "2018-05-11T15:52:26", "url": "https://files.pythonhosted.org/packages/42/b5/f7af39debb44e7f9d2c9e39e67cbe8ed50be407da7bcb7f0159a06d2b419/loggo-0.0.1-py3.6.egg" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "64b4a2665e5d3a77ea8dae6ab40dcbd5", "sha256": "add6a79049905c54d4af5e2afa92796670109f0a74571be15fba343bfa4040e3" }, "downloads": -1, "filename": "loggo-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "64b4a2665e5d3a77ea8dae6ab40dcbd5", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17742, "upload_time": "2018-05-11T15:52:24", "url": "https://files.pythonhosted.org/packages/da/bf/74785f923be311d417de4fc29877f135e37f989776d3d2671c93f740b2d3/loggo-0.1.0-py3-none-any.whl" } ], "5.0.0": [ { "comment_text": "", "digests": { "md5": "c8615a872d07663fd084ce29077139f7", "sha256": "caccd4cb7d3b9e658633096e389d8bd2b9fd2af0c9b878741bb0f1753cd60448" }, "downloads": -1, "filename": "loggo-5.0.0.tar.gz", "has_sig": false, "md5_digest": "c8615a872d07663fd084ce29077139f7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17430, "upload_time": "2019-05-29T12:25:47", "url": "https://files.pythonhosted.org/packages/ca/17/a13272f3e4672d66b3db42906f62fe46fe4b3ebad3cc0d56839aa4ec0ed2/loggo-5.0.0.tar.gz" } ], "5.1.0": [ { "comment_text": "", "digests": { "md5": "b36ce5fb011ab4e91af57954ce9c73b5", "sha256": "9372e02fa3146cc4b74814be907e6be02c24c957443b830d54f9f016d526c927" }, "downloads": -1, "filename": "loggo-5.1.0.tar.gz", "has_sig": false, "md5_digest": "b36ce5fb011ab4e91af57954ce9c73b5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17594, "upload_time": "2019-06-03T11:36:01", "url": "https://files.pythonhosted.org/packages/4d/be/84e1376ee1f13303ef7dc913c066926f7e9d71114fd2b0c185f54c7a15ec/loggo-5.1.0.tar.gz" } ], "6.0.0": [ { "comment_text": "", "digests": { "md5": "fed1c507445afce3088cbf5235a2eac9", "sha256": "fd0bf5132efb1aefc17675b91658a5c9806916fc2dcb6546c8b5efac2c6cb55b" }, "downloads": -1, "filename": "loggo-6.0.0.tar.gz", "has_sig": false, "md5_digest": "fed1c507445afce3088cbf5235a2eac9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17159, "upload_time": "2019-07-12T11:41:34", "url": "https://files.pythonhosted.org/packages/02/32/c62a6879f77153f0838fd86fd361e96d6b9a78ac63d3b9a56b7ab381e9fe/loggo-6.0.0.tar.gz" } ], "6.0.1": [ { "comment_text": "", "digests": { "md5": "078ca6b66ee9dea4358d294e74d49217", "sha256": "7dcbea742b1c4e3e1a91c6c89b8e3c313b09919145cbeccecad30bb697902405" }, "downloads": -1, "filename": "loggo-6.0.1.tar.gz", "has_sig": false, "md5_digest": "078ca6b66ee9dea4358d294e74d49217", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17155, "upload_time": "2019-07-12T14:54:00", "url": "https://files.pythonhosted.org/packages/b1/b2/d59461ea8598f6fe60b39794433809c6ca17cf83e830a2263048afe1008c/loggo-6.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "078ca6b66ee9dea4358d294e74d49217", "sha256": "7dcbea742b1c4e3e1a91c6c89b8e3c313b09919145cbeccecad30bb697902405" }, "downloads": -1, "filename": "loggo-6.0.1.tar.gz", "has_sig": false, "md5_digest": "078ca6b66ee9dea4358d294e74d49217", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17155, "upload_time": "2019-07-12T14:54:00", "url": "https://files.pythonhosted.org/packages/b1/b2/d59461ea8598f6fe60b39794433809c6ca17cf83e830a2263048afe1008c/loggo-6.0.1.tar.gz" } ] }