{"id":22549635,"url":"https://github.com/micahjsmith/stacklog","last_synced_at":"2025-04-10T01:53:12.396Z","repository":{"id":57471016,"uuid":"227196886","full_name":"micahjsmith/stacklog","owner":"micahjsmith","description":"Log stack-structured log messages","archived":false,"fork":false,"pushed_at":"2024-07-29T22:50:15.000Z","size":5955,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T03:34:56.409Z","etag":null,"topics":["logging","python"],"latest_commit_sha":null,"homepage":"https://micahjsmith.github.io/stacklog/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micahjsmith.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.rst","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-10T19:13:58.000Z","updated_at":"2024-07-29T22:49:49.000Z","dependencies_parsed_at":"2024-07-30T02:53:07.421Z","dependency_job_id":null,"html_url":"https://github.com/micahjsmith/stacklog","commit_stats":{"total_commits":30,"total_committers":1,"mean_commits":30.0,"dds":0.0,"last_synced_commit":"0ba7d5fa6f2da3c1a10a7e23c37858c4c0e4640a"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahjsmith%2Fstacklog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahjsmith%2Fstacklog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahjsmith%2Fstacklog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahjsmith%2Fstacklog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micahjsmith","download_url":"https://codeload.github.com/micahjsmith/stacklog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248142938,"owners_count":21054671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["logging","python"],"created_at":"2024-12-07T16:09:23.605Z","updated_at":"2025-04-10T01:53:12.339Z","avatar_url":"https://github.com/micahjsmith.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![PyPI Shield](https://img.shields.io/pypi/v/stacklog.svg)](https://pypi.python.org/pypi/stacklog)\n[![Downloads](https://pepy.tech/badge/stacklog)](https://pepy.tech/project/stacklog)\n[![.github/workflows/test.yml](https://github.com/micahjsmith/stacklog/actions/workflows/test.yml/badge.svg)](https://github.com/micahjsmith/stacklog/actions/workflows/test.yml)\n\n# stacklog\n\nStack log messages\n\n- Documentation: \u003chttps://micahjsmith.github.io/stacklog\u003e\n- Homepage: \u003chttps://github.com/micahjsmith/stacklog\u003e\n\n## Overview\n\nStacklog is a tiny Python library to stack log messages.\n\nA stack-structured log is an approach to logging in which log messages are (conceptually)\npushed onto a stack and emitted only when the corresponding block returns.\nStacklog provides a single method, `stacklog`, which serves as either a decorator or a\ncontext manager. This is exceptionally useful in small projects or one-off scripts.\n\nThis is illustrated best with an example:\n\n```python\nwith stacklog(print, 'Running some code'):\n    with stacklog(print, 'Running some other code'):\n        pass\n```\n\nThis produces the following logging output:\n\n```shell\nRunning some code...\nRunning some other code...\nRunning some other code...DONE\nRunning some code...DONE\n```\n\nWhen the code within a stacklog context completes, the provided message is echoed along with\nthe return status, one of `DONE` or `FAILURE`. That's pretty much it.\nCustomization and advanced features are available through callbacks.\n\n## Install\n\nstacklog has been developed and tested on Python 2.7 and 3.5+.\n\n```shell\npip install stacklog\n```\n\n## Quickstart\n\nHow often do you find yourself using the following logging anti-pattern in Python?\n\n```python\nimport logging\n\ndef a():\n    logging.info('Running a')\n    do_something()\n    logging.info('Done with a')\n\ndef b():\n    logging.info('Running b')\n    a()\n    logging.info('Done with b')\n\ntry:\n    b()\nexcept:\n    logging.info('There was an error running b')\n```\n\nThe intention here is to log the beginning and end of procedure calls for use in debugging\nor user monitoring. I call this an anti-pattern because:\n\n- it requires excessive manual attention to writing/updating logging calls at entry/exit sites\n- it results in redundant exception handling logic\n- the resulting log messages can be misleading if errors occur\n\nInstead, the approach taken by stacklog is to accomplish this using only decorators and\ncontext managers.\n\n### Usage as decorator\n\nHere is the above example using the stacklog as a decorator:\n\n```python\n@stacklog(logging.info, 'Running a')\ndef a():\n    raise Exception\n\n@stacklog(logging.info, 'Running b')\ndef b():\n    a()\n\nb()\n```\n\nThis produces logging output:\n\n```shell\nINFO:root:Running b...\nINFO:root:Running a...\nINFO:root:Running a...FAILURE\nINFO:root:Running b...FAILURE\n```\n\n### Usage as context manager\n\nHere is another example using stacklog as a context manager:\n\n```pycon\n\u003e\u003e\u003e with stacklog(logging.info, 'Running some code'):\n...     do_something()\n...\nINFO:root:Running some code...\nINFO:root:Running some code...DONE\n```\n\n## Advanced usage\n\n### Providing custom conditions\n\nA *condition* is a tuple `exception, status`. If the provided exception is raised during the\nexecution of the provided code, the provided status is logged instead of the default\n`FAILURE`.\n\n```pycon\n\u003e\u003e\u003e with stacklog(logging.info, 'Running some code', conditions=[(NotImplementedError,\n'SKIPPED')]):\n...     raise NotImplementedError\n...\nINFO:root:Running some code...\nINFO:root:Running some code...SKIPPED\n```\n\n### Customization with callbacks\n\nThe behavior of `stacklog` is fully customizable with callbacks.\n\nThe main thing that a callback will do is call the passed `stacklog` instance's\n`log` method with some custom suffix.\n\nFirst, there are three callbacks to customize the behavior of logging at the\nbeginning of the block, at successful completion of the block, and at failure\nof the block. Only one function can be registered at a time for each of\nthese events.\n\n- `on_begin(func: stacklog -\u003e None)`\n- `on_success(func: stacklog -\u003e None)`\n- `on_failure(func: stacklog -\u003e None)`\n\nSecond, one can customize failure behavior given different possible\nexceptions that are raised, by passing a pair of functions, the first to match\nan exception that was raised during block execution and the second to respond\nto the exception. Many pairs of functions can be registered, but only the most\nrecent one to be registered will be executed in the case that multiple\nfunctions match.\n\n- `on_condition(match: *exc_info -\u003e bool, func: stacklog, *exc_info -\u003e None)`\n\nThird, one can initialize and dispose of resources before and after the\nblock's execution. This is relevant for starting/stopping timers, etc. Many\nfunctions can be registered and they will all be executed.\n\n- `on_enter(func: stacklog -\u003e None)`\n- `on_exit(func: stacklog -\u003e None)`\n\nSee the implementation of `stacktime` for an example.\n\n### Adding timing information\n\nOne can customize `stacklog` with callbacks to, for example, add information\non the duration of block execution. This is packaged with the library itself\nas the `stacktime` decorator/context manager. It's usage is the same as\n`stacklog` except that it also logs timing information at the successful\ncompletion of block.\n\n```pycon\n\u003e\u003e\u003e with stacktime(print, 'Running some code', unit='ms'):\n...     time.sleep(1e-2)\n...\nRunning some code...\nRunning some code...DONE in 11.11 ms\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicahjsmith%2Fstacklog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicahjsmith%2Fstacklog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicahjsmith%2Fstacklog/lists"}