instruktai-python-logger 0.6.3__tar.gz → 0.6.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/PKG-INFO +15 -9
  2. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/README.md +14 -8
  3. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instrukt_ai_logging/install.py +12 -2
  4. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instrukt_ai_logging/logging.py +0 -7
  5. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instruktai_python_logger.egg-info/PKG-INFO +15 -9
  6. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/pyproject.toml +1 -1
  7. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/tests/test_configure_logging.py +1 -30
  8. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/tests/test_install.py +52 -0
  9. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instrukt_ai_logging/__init__.py +0 -0
  10. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instrukt_ai_logging/cli.py +0 -0
  11. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instrukt_ai_logging/py.typed +0 -0
  12. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instruktai_python_logger.egg-info/SOURCES.txt +0 -0
  13. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instruktai_python_logger.egg-info/dependency_links.txt +0 -0
  14. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instruktai_python_logger.egg-info/entry_points.txt +0 -0
  15. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/instruktai_python_logger.egg-info/top_level.txt +0 -0
  16. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/setup.cfg +0 -0
  17. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/tests/test_cli_follow.py +0 -0
  18. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/tests/test_log_aggregation.py +0 -0
  19. {instruktai_python_logger-0.6.3 → instruktai_python_logger-0.6.4}/tests/test_trace_logging.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: instruktai-python-logger
3
- Version: 0.6.3
3
+ Version: 0.6.4
4
4
  Summary: Centralized logging utilities for Python services.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -28,6 +28,10 @@ From GitHub:
28
28
  pip install git+ssh://git@github.com/InstruktAI/python-logger.git
29
29
  ```
30
30
 
31
+ For a local checkout, `make install` prepares dependencies and development
32
+ tooling only. Run `make install-runtime` separately when this user's rotation
33
+ scheduler should be wired.
34
+
31
35
  ## API
32
36
 
33
37
  - Python entrypoint: `instrukt_ai_logging.configure_logging(...)`
@@ -88,14 +92,16 @@ write its logs must not start blind.
88
92
 
89
93
  ## Rotation
90
94
 
91
- Rotation is transparent and runs entirely in user space:
92
- `configure_logging(...)` idempotently ensures a per-user rotation conf plus a
93
- per-user scheduler (a launchd LaunchAgent on macOS running `newsyslog`, a
94
- systemd user timer on Linux running `logrotate`) on every process start. No
95
- `/etc` configuration, no sudo, and no system rotation daemon ever touches
96
- these files, so rotated/recreated logs always stay owned by the producing
97
- user. Run `instrukt-ai-log-setup` to check rotation-asset status manually;
98
- normal operation never requires it.
95
+ Rotation runs entirely in user space. At deploy, run
96
+ `instrukt-ai-log-setup` once (or `make install-runtime` in this repository) to
97
+ wire the per-user rotation conf plus scheduler: a launchd LaunchAgent on macOS
98
+ running `newsyslog`, or a systemd user timer on Linux running `logrotate`.
99
+ Re-running setup on an already-wired machine reports healthy.
100
+
101
+ `configure_logging(...)` only creates and opens the log file; it never writes
102
+ rotation assets or invokes launchd/systemd. No `/etc` configuration, no sudo,
103
+ and no system rotation daemon ever touches these files, so rotated/recreated
104
+ logs always stay owned by the producing user.
99
105
 
100
106
  ## CLI
101
107
 
@@ -21,6 +21,10 @@ From GitHub:
21
21
  pip install git+ssh://git@github.com/InstruktAI/python-logger.git
22
22
  ```
23
23
 
24
+ For a local checkout, `make install` prepares dependencies and development
25
+ tooling only. Run `make install-runtime` separately when this user's rotation
26
+ scheduler should be wired.
27
+
24
28
  ## API
25
29
 
26
30
  - Python entrypoint: `instrukt_ai_logging.configure_logging(...)`
@@ -81,14 +85,16 @@ write its logs must not start blind.
81
85
 
82
86
  ## Rotation
83
87
 
84
- Rotation is transparent and runs entirely in user space:
85
- `configure_logging(...)` idempotently ensures a per-user rotation conf plus a
86
- per-user scheduler (a launchd LaunchAgent on macOS running `newsyslog`, a
87
- systemd user timer on Linux running `logrotate`) on every process start. No
88
- `/etc` configuration, no sudo, and no system rotation daemon ever touches
89
- these files, so rotated/recreated logs always stay owned by the producing
90
- user. Run `instrukt-ai-log-setup` to check rotation-asset status manually;
91
- normal operation never requires it.
88
+ Rotation runs entirely in user space. At deploy, run
89
+ `instrukt-ai-log-setup` once (or `make install-runtime` in this repository) to
90
+ wire the per-user rotation conf plus scheduler: a launchd LaunchAgent on macOS
91
+ running `newsyslog`, or a systemd user timer on Linux running `logrotate`.
92
+ Re-running setup on an already-wired machine reports healthy.
93
+
94
+ `configure_logging(...)` only creates and opens the log file; it never writes
95
+ rotation assets or invokes launchd/systemd. No `/etc` configuration, no sudo,
96
+ and no system rotation daemon ever touches these files, so rotated/recreated
97
+ logs always stay owned by the producing user.
92
98
 
93
99
  ## CLI
94
100
 
@@ -155,9 +155,19 @@ def _ensure_launchd_loaded(plist_path: Path) -> list[str]:
155
155
  except (OSError, subprocess.TimeoutExpired) as exc:
156
156
  return [f"launchctl bootstrap failed to run: {exc}"]
157
157
 
158
- if result.returncode != 0 and "already bootstrapped" not in result.stderr.lower():
158
+ if result.returncode == 0 or "already bootstrapped" in result.stderr.lower():
159
+ return []
160
+
161
+ # macOS reports EIO(5), not "already bootstrapped", when re-bootstrapping an already-loaded agent.
162
+ # Confirm with `print` exit status; a nonzero result preserves the original bootstrap failure.
163
+ try:
164
+ loaded_result = _run_scheduler_command(["launchctl", "print", f"gui/{uid}/{_LAUNCHD_LABEL}"])
165
+ except (OSError, subprocess.TimeoutExpired):
159
166
  return [f"launchctl bootstrap failed: {result.stderr.strip()}"]
160
- return []
167
+
168
+ if loaded_result.returncode == 0:
169
+ return []
170
+ return [f"launchctl bootstrap failed: {result.stderr.strip()}"]
161
171
 
162
172
 
163
173
  def _ensure_systemd_loaded() -> list[str]:
@@ -12,8 +12,6 @@ from logging.handlers import WatchedFileHandler
12
12
  from pathlib import Path
13
13
  from typing import Any, Protocol, cast, runtime_checkable
14
14
 
15
- from instrukt_ai_logging.install import ensure_rotation
16
-
17
15
  # Standard logging levels are: NOTSET=0, DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50
18
16
  TRACE: int = 5
19
17
  logging.addLevelName(TRACE, "TRACE")
@@ -485,11 +483,6 @@ def configure_logging(
485
483
  for prefix in muted:
486
484
  logging.getLogger(prefix).setLevel(logging.WARNING)
487
485
 
488
- # Rotation bootstrap is not logging: a failure here is surfaced as a
489
- # warning, never fatal to an already-working log file.
490
- for problem in ensure_rotation():
491
- logging.getLogger(app_logger_prefix).warning("log rotation ensure problem: %s", problem)
492
-
493
486
  return log_file
494
487
 
495
488
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: instruktai-python-logger
3
- Version: 0.6.3
3
+ Version: 0.6.4
4
4
  Summary: Centralized logging utilities for Python services.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -28,6 +28,10 @@ From GitHub:
28
28
  pip install git+ssh://git@github.com/InstruktAI/python-logger.git
29
29
  ```
30
30
 
31
+ For a local checkout, `make install` prepares dependencies and development
32
+ tooling only. Run `make install-runtime` separately when this user's rotation
33
+ scheduler should be wired.
34
+
31
35
  ## API
32
36
 
33
37
  - Python entrypoint: `instrukt_ai_logging.configure_logging(...)`
@@ -88,14 +92,16 @@ write its logs must not start blind.
88
92
 
89
93
  ## Rotation
90
94
 
91
- Rotation is transparent and runs entirely in user space:
92
- `configure_logging(...)` idempotently ensures a per-user rotation conf plus a
93
- per-user scheduler (a launchd LaunchAgent on macOS running `newsyslog`, a
94
- systemd user timer on Linux running `logrotate`) on every process start. No
95
- `/etc` configuration, no sudo, and no system rotation daemon ever touches
96
- these files, so rotated/recreated logs always stay owned by the producing
97
- user. Run `instrukt-ai-log-setup` to check rotation-asset status manually;
98
- normal operation never requires it.
95
+ Rotation runs entirely in user space. At deploy, run
96
+ `instrukt-ai-log-setup` once (or `make install-runtime` in this repository) to
97
+ wire the per-user rotation conf plus scheduler: a launchd LaunchAgent on macOS
98
+ running `newsyslog`, or a systemd user timer on Linux running `logrotate`.
99
+ Re-running setup on an already-wired machine reports healthy.
100
+
101
+ `configure_logging(...)` only creates and opens the log file; it never writes
102
+ rotation assets or invokes launchd/systemd. No `/etc` configuration, no sudo,
103
+ and no system rotation daemon ever touches these files, so rotated/recreated
104
+ logs always stay owned by the producing user.
99
105
 
100
106
  ## CLI
101
107
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "instruktai-python-logger"
7
- version = "0.6.3"
7
+ version = "0.6.4"
8
8
  description = "Centralized logging utilities for Python services."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
  from tempfile import TemporaryDirectory
6
6
 
7
7
  import pytest
8
- from instrukt_ai_logging import InstruktAILogger, configure_logging, get_logger, install
8
+ from instrukt_ai_logging import InstruktAILogger, configure_logging, get_logger
9
9
 
10
10
  # Log markers shared by each test and its assertions — named constants per
11
11
  # software-development/procedure/snapshot-testing (no bare literals in content
@@ -41,8 +41,6 @@ _FIELD_SESSION = f"session={_KV_SESSION}"
41
41
  _FIELD_N = f"n={_KV_N}"
42
42
 
43
43
  _APP_NAME = "teleclaude"
44
- _ROTATION_PROBLEM_MARKER = "log rotation ensure problem"
45
- _ROTATION_FAILURE_REASON = "no session bus"
46
44
 
47
45
 
48
46
  @pytest.fixture()
@@ -121,33 +119,6 @@ def test_configure_logging_fails_fast_when_file_unwritable(isolated_logging, mon
121
119
  os.chmod(log_path, 0o644)
122
120
 
123
121
 
124
- class _FakeFailingCompletedProcess:
125
- def __init__(self) -> None:
126
- self.returncode = 1
127
- self.stderr = _ROTATION_FAILURE_REASON
128
- self.stdout = ""
129
-
130
-
131
- def test_configure_logging_warns_without_raising_when_rotation_ensure_fails(isolated_logging, monkeypatch):
132
- with TemporaryDirectory() as tmp:
133
- monkeypatch.setenv("XDG_STATE_HOME", tmp)
134
- monkeypatch.setenv("TELECLAUDE_LOG_LEVEL", "INFO")
135
- monkeypatch.setenv("TELECLAUDE_THIRD_PARTY_LOG_LEVEL", "WARNING")
136
-
137
- def _fake_run(args):
138
- return _FakeFailingCompletedProcess()
139
-
140
- monkeypatch.setattr(install, "_run_scheduler_command", _fake_run)
141
-
142
- # A rotation-ensure failure must never crash logging — it's surfaced
143
- # as a WARNING through the configured logger, not raised.
144
- log_path = configure_logging(_APP_NAME)
145
-
146
- content = _read_text(log_path)
147
- assert _ROTATION_PROBLEM_MARKER in content
148
- assert _ROTATION_FAILURE_REASON in content
149
-
150
-
151
122
  def test_configure_logging_resolves_xdg_state_home_location(isolated_logging, monkeypatch):
152
123
  with TemporaryDirectory() as tmp:
153
124
  monkeypatch.setenv("XDG_STATE_HOME", tmp)
@@ -223,6 +223,58 @@ def test_ensure_rotation_tolerates_already_bootstrapped_launchd(
223
223
  assert problems == []
224
224
 
225
225
 
226
+ @pytest.mark.functional
227
+ def test_main_treats_print_confirmed_launchd_eio_as_healthy(
228
+ rotation_env: Path, monkeypatch: pytest.MonkeyPatch
229
+ ) -> None:
230
+ monkeypatch.setattr(sys, "platform", "darwin")
231
+
232
+ def _fake_run(args: list[str]) -> _FakeCompletedProcess:
233
+ if args[1] == "bootstrap":
234
+ return _FakeCompletedProcess(returncode=5, stderr="Bootstrap failed: 5: Input/output error")
235
+ return _FakeCompletedProcess(returncode=0)
236
+
237
+ monkeypatch.setattr(install, "_run_scheduler_command", _fake_run)
238
+
239
+ install.main()
240
+
241
+
242
+ @pytest.mark.functional
243
+ def test_main_reports_unconfirmed_launchd_eio(rotation_env: Path, monkeypatch: pytest.MonkeyPatch) -> None:
244
+ monkeypatch.setattr(sys, "platform", "darwin")
245
+
246
+ def _fake_run(args: list[str]) -> _FakeCompletedProcess:
247
+ if args[1] == "bootstrap":
248
+ return _FakeCompletedProcess(returncode=5, stderr="Bootstrap failed: 5: Input/output error")
249
+ return _FakeCompletedProcess(returncode=1)
250
+
251
+ monkeypatch.setattr(install, "_run_scheduler_command", _fake_run)
252
+
253
+ with pytest.raises(SystemExit) as exc_info:
254
+ install.main()
255
+
256
+ assert exc_info.value.code == 1
257
+
258
+
259
+ @pytest.mark.functional
260
+ def test_main_reports_launchd_eio_when_discriminator_times_out(
261
+ rotation_env: Path, monkeypatch: pytest.MonkeyPatch
262
+ ) -> None:
263
+ monkeypatch.setattr(sys, "platform", "darwin")
264
+
265
+ def _fake_run(args: list[str]) -> _FakeCompletedProcess:
266
+ if args[1] == "bootstrap":
267
+ return _FakeCompletedProcess(returncode=5, stderr="Bootstrap failed: 5: Input/output error")
268
+ raise subprocess.TimeoutExpired(cmd=args, timeout=install._SCHEDULER_COMMAND_TIMEOUT_S)
269
+
270
+ monkeypatch.setattr(install, "_run_scheduler_command", _fake_run)
271
+
272
+ with pytest.raises(SystemExit) as exc_info:
273
+ install.main()
274
+
275
+ assert exc_info.value.code == 1
276
+
277
+
226
278
  def test_main_prints_status_and_exits_zero_when_healthy(
227
279
  rotation_env: Path,
228
280
  successful_subprocess: list[list[str]],