{"id":22730071,"url":"https://github.com/simonrob/pyoslog","last_synced_at":"2025-06-24T04:32:12.123Z","repository":{"id":57698514,"uuid":"488348817","full_name":"simonrob/pyoslog","owner":"simonrob","description":"Send messages to the macOS unified logging system from Python","archived":false,"fork":false,"pushed_at":"2025-05-22T13:18:55.000Z","size":88,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-22T14:51:21.389Z","etag":null,"topics":["logging","logging-framework","logging-library","macos","oslog","python","unified-logging"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonrob.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-05-03T20:09:40.000Z","updated_at":"2025-05-22T13:18:58.000Z","dependencies_parsed_at":"2025-04-13T23:14:20.811Z","dependency_job_id":"b7f885a8-e10e-4353-93f9-5a5f8e4c4ea5","html_url":"https://github.com/simonrob/pyoslog","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/simonrob/pyoslog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonrob%2Fpyoslog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonrob%2Fpyoslog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonrob%2Fpyoslog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonrob%2Fpyoslog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonrob","download_url":"https://codeload.github.com/simonrob/pyoslog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonrob%2Fpyoslog/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261604153,"owners_count":23183600,"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","logging-framework","logging-library","macos","oslog","python","unified-logging"],"created_at":"2024-12-10T18:13:20.126Z","updated_at":"2025-06-24T04:32:12.103Z","avatar_url":"https://github.com/simonrob.png","language":"Python","readme":"# Pyoslog\nPyoslog allows you to send messages to the macOS [unified logging system](https://developer.apple.com/documentation/os/os_log) using Python.\n\n```python\nfrom pyoslog import os_log, OS_LOG_DEFAULT\nos_log(OS_LOG_DEFAULT, 'Hello from Python!')\n```\n\n\n## Installation\nPyoslog requires macOS 10.12 or later and Python 3.6 or later.\nInstall from [PyPI](https://pypi.org/project/pyoslog/) using `pip`:\n\n```shell\npython -m pip install pyoslog\n```\n\nThe module will install and import without error on earlier macOS versions, or on unsupported Operating Systems or incompatible Python versions.\nUse `pyoslog.is_supported()` if you need to support incompatible environments and want to know at runtime whether to use pyoslog.\nPlease note that if `is_supported()` returns `False` then none of the module's other methods or constants will exist.\n\n\n## Usage\n\n```python\nimport pyoslog\nif pyoslog.is_supported():\n    pyoslog.log('This is an OS_LOG_TYPE_DEFAULT message via pyoslog')\n```\n\n### Available methods\nPyoslog provides the following methods from Apple's [unified logging header](https://opensource.apple.com/source/xnu/xnu-3789.21.4/libkern/os/log.h.auto.html):\n- [`os_log_create`](https://developer.apple.com/documentation/os/1643744-os_log_create)\n- [`os_log_type_enabled`](https://developer.apple.com/documentation/os/1643749-os_log_type_enabled) (and [`info`](https://developer.apple.com/documentation/os/os_log_info_enabled)/[`debug`](https://developer.apple.com/documentation/os/os_log_debug_enabled) variants)\n- [`os_log_with_type`](https://developer.apple.com/documentation/os/os_log_with_type)\n- [`os_log`](https://developer.apple.com/documentation/os/os_log) (and [`info`](https://developer.apple.com/documentation/os/os_log_info)/[`debug`](https://developer.apple.com/documentation/os/os_log_debug)/[`error`](https://developer.apple.com/documentation/os/os_log_error)/[`fault`](https://developer.apple.com/documentation/os/os_log_fault) variants).\n\nAll the pyoslog methods have the same signatures as their native versions, _except_ for where a method requires a `format` parameter.\nThe `os_log` system requires a constant (static) format specifier, and it is not possible to achieve this via Python.\nAs a result, all instances of format strings use `\"%{public}s\"`, and all messages are converted to a string before passing to the native methods.\n\nPyoslog also offers a helper method – `log` – that by default posts a message of type `OS_LOG_TYPE_DEFAULT` to `OS_LOG_DEFAULT`.\nFor example, the shortcut `log('message')` is equivalent to `os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, 'message')`.\n\nThe `Handler` class is designed for use with Python's inbuilt [logging](https://docs.python.org/3/library/logging.html) module.\nIt works as a drop-in replacement for other Handler varieties.\n\nSee [pyoslog's method documentation](https://pyoslog.readthedocs.io/en/latest/reference.html) for a full reference. \n\n### Labelling subsystem and category\nCreate a log object using `os_log_create` and pass it to any of the log methods to add your own subsystem and category labels:\n\n```python\nimport pyoslog\nlog = pyoslog.os_log_create('ac.robinson.pyoslog', 'custom-category')\npyoslog.os_log_with_type(log, pyoslog.OS_LOG_TYPE_DEBUG, 'Message to log object', log, 'of type', pyoslog.OS_LOG_TYPE_DEBUG)\n```\n\n### Enabling and disabling log output\nLog output can be enabled or disabled globally by switching between the desired log object and `pyoslog.OS_LOG_DISABLED`:\n\n```python\nimport pyoslog\nlog = pyoslog.OS_LOG_DEFAULT\npyoslog.os_log(log, 'Log output enabled')  # will appear in the unified log\nlog = pyoslog.OS_LOG_DISABLED\npyoslog.os_log(log, 'Log output disabled')  # will not appear in the unified log\n```\n\nIt is also possible to check whether individual log types are enabled for a particular log object:\n\n```python\nimport pyoslog\npyoslog.os_log_type_enabled(pyoslog.OS_LOG_DEFAULT, pyoslog.OS_LOG_TYPE_DEBUG)\n```\n\nIt is not possible to directly set a log object's mode from Python, but see the [`config` section of `man log`](https://keith.github.io/xcode-man-pages/log.1.html#config) for documentation about doing this in `sudo` mode.\n\n### Integration with the logging module\nUse the pyoslog `Handler` to direct messages to pyoslog:\n\n```python\nimport logging, pyoslog\nhandler = pyoslog.Handler()\nhandler.setSubsystem('org.example.your-app', 'filter-category')\nlogger = logging.getLogger()\nlogger.addHandler(handler)\nlogger.error('message')\n```\n\nLogger levels are mapped internally to the `OS_LOG_TYPE_*` values – for example, `logger.debug('message')` will generate a message of type `OS_LOG_TYPE_DEBUG`.\n\n### Receiving log messages\nLogs can be viewed using Console.app or the `log` command.\nFor example, messages sent using the default configuration can be streamed using:\n\n```shell\nlog stream --predicate 'processImagePath CONTAINS [c] \"python\"'\n```\n\nMessages sent using custom log objects can be filtered more precisely.\nFor example, to receive messages from the labelled subsystem used in the example above:\n\n```shell\nlog stream --predicate 'subsystem == \"ac.robinson.pyoslog\"' --level debug\n```\n\nSee the `log` tool's manpages (`man log` or [online](https://keith.github.io/xcode-man-pages/log.1.html)) for further details about the available options and filters.\n\n### Handling cleanup\nWhen labelling subsystem and category using the native C methods there is a requirement to free the log object after use (using [`os_release`](https://developer.apple.com/documentation/os/1524245-os_release)).\nThe pyoslog module handles this for you – there is no need to `del` or release these objects.\n\n\n## Limitations\nAs noted above, while the macOS `os_log` API allows use of a format string with many methods, this parameter is required to be a C string literal.\nAs a result, pyoslog hardcodes all format strings to `\"%{public}s\"`.\n\n\n## Testing\nThe pyoslog module's tests require the [pyobjc OSLog framework wrappers](https://pypi.org/project/pyobjc-framework-OSLog/) and the [storeWithScope initialiser](https://developer.apple.com/documentation/oslog/oslogstore/3548057-storewithscope) in order to verify output so, as a result, can only be run on macOS 12 or later.\n\nAfter installing the OSLog wrappers (via `python -m pip install pyobjc-framework-OSLog`), navigate to the [tests](https://github.com/simonrob/pyoslog/tree/main/tests) directory and run:\n\n```shell\npython -m unittest\n```\n\nAll of pyoslog's code is covered by tests, but please note that if Console.app is live-streaming messages, some tests may fail.\nSee [`test_logging.py`](https://github.com/simonrob/pyoslog/blob/main/tests/test_logging.py#L99) for discussion about why this is the case.\n\n\n## Alternatives\nAt the time this module was created there were no alternatives available on [PyPI](https://pypi.org/search/?q=macos+unified+logging\u0026c=Operating+System+%3A%3A+MacOS).\nSince then, the [macos-oslog](https://pypi.org/project/macos-oslog/) module has been released, with broadly equivalent functionality to pyoslog, except for the need to manually release the log object.\nThere is also [os-signpost](https://pypi.org/project/os-signpost/), which uses `cython` to provide the [`OSSignposter`](https://developer.apple.com/documentation/os/ossignposter) API, and could easily be extended to provide `os_log` functionality.\n\nIn addition, there are other options available if PyPI access is not seen as a constraint:\n\n- [apple_os_log_py](https://github.com/cedar101/apple_os_log_py)\n- [pymacoslog](https://github.com/douglas-carmichael/pymacoslog)\n- [loggy](https://github.com/pointy-tools/loggy)\n\nNote that the [pyobjc](https://pyobjc.readthedocs.io/) module [OSLog](https://pypi.org/project/pyobjc-framework-OSLog/) is for _reading_ from the unified logging system rather than writing to it (and as a result is used for testing pyoslog).\nA `log.h` binding is on that project's [roadmap](https://github.com/ronaldoussoren/pyobjc/issues/377), but not yet implemented. \n\n\n## License\n[Apache 2.0](https://github.com/simonrob/pyoslog/blob/main/LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonrob%2Fpyoslog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonrob%2Fpyoslog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonrob%2Fpyoslog/lists"}