Skip to content

Commit 8777bb0

Browse files
committed
Version 0.6.0: add _enabled methods, typing, improved tests, docs
1 parent eb6766a commit 8777bb0

19 files changed

+804
-105
lines changed

.gitignore

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ dmypy.json
129129
.pyre/
130130

131131
# Custom for this repository
132-
versions
133-
build.sh
134-
.idea
135132
*.iml
133+
.idea
134+
build.sh
135+
versions
136+
137+
# duplicate of master readme (to integrate in docs)
138+
docs/readme.md

README.md

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Pyoslog
2-
Pyoslog is a simple Python module that allows you to send messages to the macOS [unified logging system](https://developer.apple.com/documentation/os/os_log).
2+
Pyoslog allows you to send messages to the macOS [unified logging system](https://developer.apple.com/documentation/os/os_log) using Python.
33

44
```python
55
from pyoslog import os_log, OS_LOG_DEFAULT
@@ -8,27 +8,37 @@ os_log(OS_LOG_DEFAULT, 'Hello from Python!')
88

99

1010
## Installation
11-
Pyoslog requires macOS 10.12 or later.
11+
Pyoslog requires macOS 10.12 or later and Python 3.6 or later.
1212
Install using `pip`:
1313

1414
```shell
1515
python -m pip install pyoslog
1616
```
1717

18-
The module will install and import without error on earlier macOS versions (and on unsupported Operating Systems and Python versions).
19-
Use `pyoslog.is_supported()` if you need to support old macOS versions or other environments and want to know at runtime whether to use pyoslog.
18+
The module will install and import without error on earlier macOS versions, or on unsupported Operating Systems or incompatible Python versions.
19+
Use `pyoslog.is_supported()` if you need to support incompatible environments and want to know at runtime whether to use pyoslog.
2020
Please note that if `is_supported()` returns `False` then none of the module's other methods or constants will exist.
2121

2222

2323
## Usage
24-
Pyoslog currently provides the methods [`os_log_create`](https://developer.apple.com/documentation/os/1643744-os_log_create), [`os_log_with_type`](https://developer.apple.com/documentation/os/os_log_with_type) and [`os_log`](https://developer.apple.com/documentation/os/os_log), each with the same signatures as their native versions.
24+
Pyoslog currently provides the following methods:
25+
- [`os_log_create`](https://developer.apple.com/documentation/os/1643744-os_log_create)
26+
- [`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)
27+
- [`os_log_with_type`](https://developer.apple.com/documentation/os/os_log_with_type)
28+
- [`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).
2529

26-
The module also offers a helper method – `log` – that by default posts a message of type `OS_LOG_TYPE_DEFAULT` to `OS_LOG_DEFAULT`.
30+
All the pyoslog methods have the same signatures as their native versions, _except_ for where a method requires a `format` parameter.
31+
The `os_log` system requires a constant (static) format specifier, and it is not possible to achieve this via Python.
32+
As a result, all instances of format strings use `"%{public}s"`, and all messages are converted to a string before passing to the native methods.
33+
34+
Pyoslog also offers a helper method – `log` – that by default posts a message of type `OS_LOG_TYPE_DEFAULT` to `OS_LOG_DEFAULT`.
2735
For example, the shortcut `log('message')` is equivalent to `os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, 'message')`.
2836

2937
The `Handler` class is designed for use with Python's inbuilt [logging](https://docs.python.org/3/library/logging.html) module.
3038
It works as a drop-in replacement for other Handler varieties.
3139

40+
See [pyoslog's Read the Docs entry](https://pyoslog.readthedocs.io/) for a full reference.
41+
3242
### Labelling subsystem and category
3343
Create a log object using `os_log_create` and pass it to any of the log methods to add your own subsystem and category labels:
3444

@@ -38,6 +48,26 @@ log = pyoslog.os_log_create('ac.robinson.pyoslog', 'custom-category')
3848
pyoslog.os_log_with_type(log, pyoslog.OS_LOG_TYPE_DEBUG, 'Message to log object', log, 'of type', pyoslog.OS_LOG_TYPE_DEBUG)
3949
```
4050

51+
### Enabling and disabling log output
52+
Log output can be enabled or disabled globally by switching between the desired log object and `pyoslog.OS_LOG_DISABLED`:
53+
54+
```python
55+
import pyoslog
56+
log = pyoslog.OS_LOG_DEFAULT
57+
pyoslog.os_log(log, 'Log output enabled')
58+
log = pyoslog.OS_LOG_DISABLED
59+
pyoslog.os_log(log, 'Log output disabled')
60+
```
61+
62+
It is also possible to check whether individual log types are enabled for a particular log object:
63+
64+
```python
65+
import pyoslog
66+
pyoslog.os_log_type_enabled(pyoslog.OS_LOG_DEFAULT, pyoslog.OS_LOG_TYPE_DEBUG)
67+
```
68+
69+
It is not possible to directly set a log object's mode from Python, but see the `config` section of `man log` for documentation about doing this in `sudo` mode.
70+
4171
### Integration with the logging module
4272
Use the pyoslog `Handler` to direct messages to pyoslog:
4373

@@ -59,14 +89,14 @@ Logs can be viewed using Console.app or the `log` command.
5989
For example, messages sent using the default configuration can be streamed using:
6090

6191
```shell
62-
log stream --predicate 'processImagePath CONTAINS "Python"'
92+
log stream --predicate 'processImagePath CONTAINS [c] "python"'
6393
```
6494

65-
Messages sent using custom configurations can be filtered more precisely.
95+
Messages sent using custom log objects can be filtered more precisely.
6696
For example, to receive messages from the labelled subsystem used in the example above:
6797

6898
```shell
69-
log stream --predicate 'subsystem == "ac.robinson.pyoslog"' --level=debug
99+
log stream --predicate 'subsystem == "ac.robinson.pyoslog"' --level debug
70100
```
71101

72102
See `man log` for further details about the available options and filters.
@@ -84,11 +114,14 @@ After installing the OSLog wrappers (via `python -m pip install pyobjc-framework
84114
python -m unittest
85115
```
86116

117+
Please note that if Console.app is live-streaming messages, some tests may fail.
118+
See [`test_logging.py`](https://github.com/simonrob/pyoslog/blob/main/tests/test_logging.py#L84) for discussion about why this is the case.
119+
87120

88121
## Alternatives
89122
At the time this module was created there were no alternatives available on [PyPi](https://pypi.org/search/?q=macos+unified+logging&c=Operating+System+%3A%3A+MacOS).
90123
Since then, the [macos-oslog](https://pypi.org/project/macos-oslog/) module has been released, with broadly equivalent functionality to pyoslog.
91-
There are also other options available if PyPi access is not seen as a constraint:
124+
In addition, there are other options available if PyPi access is not seen as a constraint:
92125

93126
- [apple_os_log_py](https://github.com/cedar101/apple_os_log_py)
94127
- [pymacoslog](https://github.com/douglas-carmichael/pymacoslog)

docs/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = .
9+
BUILDDIR = _build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

docs/_static/custom.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.function, .method {
2+
margin-bottom: 1em;
3+
}

docs/conf.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# For the full list of built-in configuration values, see the documentation:
4+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
6+
import datetime
7+
import os
8+
import sys
9+
10+
# Make sure pyoslog's source files are detected
11+
sys.path.insert(0, os.path.abspath('..'))
12+
13+
# Get properties from __version__.py
14+
about = {}
15+
with open(os.path.join(os.path.abspath('..'), 'pyoslog', '__version__.py')) as version_file:
16+
exec(version_file.read(), about)
17+
18+
# Import the main README.md
19+
with open(os.path.join(os.path.abspath('.'), 'readme.md'), 'w') as output_file:
20+
output_file.write("# Overview\n", )
21+
lines = []
22+
with open(os.path.join(os.path.abspath('..'), 'README.md')) as readme:
23+
for line in readme:
24+
if line.startswith('# '): # skip main title (we name it 'Overview' above)
25+
continue
26+
lines.append(line.rstrip())
27+
output_file.write('\n'.join(lines))
28+
29+
# -- Project information -----------------------------------------------------
30+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
31+
32+
project = about['__title__']
33+
34+
# noinspection PyShadowingBuiltins
35+
copyright = '%d, %s' % (datetime.datetime.now().year, about['__author__'])
36+
author = about['__author__']
37+
version = about['__version__']
38+
release = about['__version__']
39+
40+
print('Documenting', project, version)
41+
42+
# -- General configuration ---------------------------------------------------
43+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
44+
45+
extensions = [
46+
'sphinx.ext.autodoc',
47+
'sphinx.ext.viewcode',
48+
'recommonmark' # note: https://github.com/readthedocs/recommonmark/issues/177
49+
]
50+
source_suffix = ['.rst', '.md']
51+
52+
autodoc_member_order = 'bysource' # note: doesn't work with inherited members: github.com/sphinx-doc/sphinx/issues/628
53+
autodoc_preserve_defaults = True # better display of log() defaults
54+
55+
templates_path = ['_templates']
56+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
57+
58+
# -- Options for HTML output -------------------------------------------------
59+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
60+
61+
html_static_path = ['_static']
62+
html_theme = 'alabaster'

docs/index.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Pyoslog
2+
=======
3+
Send messages to the macOS `unified logging system <https://developer.apple.com/documentation/os/os_log>`_ using Python.
4+
5+
6+
Table of contents
7+
+++++++++++++++++
8+
.. toctree::
9+
:maxdepth: 3
10+
11+
readme
12+
13+
reference
14+
15+
* :ref:`genindex`

docs/make.bat

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@ECHO OFF
2+
3+
pushd %~dp0
4+
5+
REM Command file for Sphinx documentation
6+
7+
if "%SPHINXBUILD%" == "" (
8+
set SPHINXBUILD=sphinx-build
9+
)
10+
set SOURCEDIR=.
11+
set BUILDDIR=_build
12+
13+
%SPHINXBUILD% >NUL 2>NUL
14+
if errorlevel 9009 (
15+
echo.
16+
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17+
echo.installed, then set the SPHINXBUILD environment variable to point
18+
echo.to the full path of the 'sphinx-build' executable. Alternatively you
19+
echo.may add the Sphinx directory to PATH.
20+
echo.
21+
echo.If you don't have Sphinx installed, grab it from
22+
echo.https://www.sphinx-doc.org/
23+
exit /b 1
24+
)
25+
26+
if "%1" == "" goto help
27+
28+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29+
goto end
30+
31+
:help
32+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33+
34+
:end
35+
popd

docs/reference.rst

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
Reference
2+
=========
3+
See `Apple's documentation <https://developer.apple.com/documentation/os/logging?language=objc>`_ for further
4+
information about macOS logging.
5+
6+
7+
Constants
8+
+++++++++
9+
10+
Log objects
11+
------------
12+
13+
.. py:data:: pyoslog.OS_LOG_DEFAULT
14+
:type: os_log_t
15+
:value: The shared disabled log.
16+
17+
.. py:data:: pyoslog.OS_LOG_DISABLED
18+
:type: os_log_t
19+
:value: The shared default log.
20+
21+
Log levels/types
22+
----------------
23+
24+
.. py:data:: pyoslog.OS_LOG_TYPE_DEBUG
25+
:type: int
26+
:value: The debug log level.
27+
28+
.. py:data:: pyoslog.OS_LOG_TYPE_INFO
29+
:type: int
30+
:value: The informational log level.
31+
32+
.. py:data:: pyoslog.OS_LOG_TYPE_DEFAULT
33+
:type: int
34+
:value: The default log level.
35+
36+
.. py:data:: pyoslog.OS_LOG_TYPE_ERROR
37+
:type: int
38+
:value: The error log level.
39+
40+
.. py:data:: pyoslog.OS_LOG_TYPE_FAULT
41+
:type: int
42+
:value: The fault log level.
43+
44+
45+
Methods
46+
+++++++
47+
48+
.. automodule:: pyoslog
49+
:imported-members:
50+
:members:
51+
:exclude-members: Handler
52+
53+
54+
Handler
55+
+++++++
56+
57+
.. autoclass:: pyoslog.Handler
58+
:members:

pyoslog/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
""""Send messages to the macOS unified logging system. See: https://developer.apple.com/documentation/os/os_log"""
21
from .compatibility import is_supported
32

43
if is_supported():
54
from .core import *
65
from .handler import *
76

8-
del compatibility
7+
# remove globals so they are not revealed to importers
8+
del core # type: ignore
9+
del handler # type: ignore
10+
11+
del py_object
12+
del os_log_t
13+
14+
del compatibility # type: ignore

pyoslog/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__title__ = 'pyoslog'
2-
__version__ = '0.5.0'
2+
__version__ = '0.6.0'
33
__description__ = 'Send messages to the macOS unified logging system'
44
__author__ = 'Simon Robinson'
55
__author_email__ = 'simon@robinson.ac'

0 commit comments

Comments
 (0)