cloud-dog-logging 0.4.0__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 (109) hide show
  1. cloud_dog_logging-0.4.0/.docs-manifest.yml +6 -0
  2. cloud_dog_logging-0.4.0/.gitignore +16 -0
  3. cloud_dog_logging-0.4.0/AGENT-INSTRUCTION-FIX-LOGGING.md +133 -0
  4. cloud_dog_logging-0.4.0/ARCHITECTURE.md +475 -0
  5. cloud_dog_logging-0.4.0/BUILD.md +73 -0
  6. cloud_dog_logging-0.4.0/CHANGELOG.md +49 -0
  7. cloud_dog_logging-0.4.0/DATA-MODEL.md +33 -0
  8. cloud_dog_logging-0.4.0/LICENCE +190 -0
  9. cloud_dog_logging-0.4.0/LICENSE +176 -0
  10. cloud_dog_logging-0.4.0/NOTICE +7 -0
  11. cloud_dog_logging-0.4.0/PKG-INFO +23 -0
  12. cloud_dog_logging-0.4.0/README.md +92 -0
  13. cloud_dog_logging-0.4.0/REQUIREMENTS.md +282 -0
  14. cloud_dog_logging-0.4.0/TESTS.md +404 -0
  15. cloud_dog_logging-0.4.0/adoption_test.py +95 -0
  16. cloud_dog_logging-0.4.0/cloud_dog_logging/GAPS.md +38 -0
  17. cloud_dog_logging-0.4.0/cloud_dog_logging/__init__.py +406 -0
  18. cloud_dog_logging-0.4.0/cloud_dog_logging/app_logger.py +143 -0
  19. cloud_dog_logging-0.4.0/cloud_dog_logging/audit_logger.py +333 -0
  20. cloud_dog_logging-0.4.0/cloud_dog_logging/audit_schema.py +237 -0
  21. cloud_dog_logging-0.4.0/cloud_dog_logging/batching.py +86 -0
  22. cloud_dog_logging-0.4.0/cloud_dog_logging/compat.py +94 -0
  23. cloud_dog_logging-0.4.0/cloud_dog_logging/config.py +248 -0
  24. cloud_dog_logging-0.4.0/cloud_dog_logging/correlation.py +100 -0
  25. cloud_dog_logging-0.4.0/cloud_dog_logging/errors.py +35 -0
  26. cloud_dog_logging-0.4.0/cloud_dog_logging/event_catalogue.py +76 -0
  27. cloud_dog_logging-0.4.0/cloud_dog_logging/exceptions.py +43 -0
  28. cloud_dog_logging-0.4.0/cloud_dog_logging/field_providers.py +227 -0
  29. cloud_dog_logging-0.4.0/cloud_dog_logging/formatters/__init__.py +64 -0
  30. cloud_dog_logging-0.4.0/cloud_dog_logging/formatters/json_formatter.py +326 -0
  31. cloud_dog_logging-0.4.0/cloud_dog_logging/formatters/text_formatter.py +88 -0
  32. cloud_dog_logging-0.4.0/cloud_dog_logging/handler_types.py +103 -0
  33. cloud_dog_logging-0.4.0/cloud_dog_logging/handlers/__init__.py +28 -0
  34. cloud_dog_logging-0.4.0/cloud_dog_logging/handlers/dual_handler.py +82 -0
  35. cloud_dog_logging-0.4.0/cloud_dog_logging/handlers/rotating_file.py +210 -0
  36. cloud_dog_logging-0.4.0/cloud_dog_logging/handlers/stdout_handler.py +49 -0
  37. cloud_dog_logging-0.4.0/cloud_dog_logging/health/__init__.py +26 -0
  38. cloud_dog_logging-0.4.0/cloud_dog_logging/health/reporter.py +121 -0
  39. cloud_dog_logging-0.4.0/cloud_dog_logging/integrity.py +223 -0
  40. cloud_dog_logging-0.4.0/cloud_dog_logging/middleware/__init__.py +27 -0
  41. cloud_dog_logging-0.4.0/cloud_dog_logging/middleware/audit.py +261 -0
  42. cloud_dog_logging-0.4.0/cloud_dog_logging/middleware/fastapi.py +163 -0
  43. cloud_dog_logging-0.4.0/cloud_dog_logging/presets.py +80 -0
  44. cloud_dog_logging-0.4.0/cloud_dog_logging/redaction.py +207 -0
  45. cloud_dog_logging-0.4.0/cloud_dog_logging/sampling.py +82 -0
  46. cloud_dog_logging-0.4.0/cloud_dog_logging/signing.py +78 -0
  47. cloud_dog_logging-0.4.0/cloud_dog_logging/sinks/__init__.py +41 -0
  48. cloud_dog_logging-0.4.0/cloud_dog_logging/sinks/base.py +52 -0
  49. cloud_dog_logging-0.4.0/cloud_dog_logging/sinks/db_sink.py +67 -0
  50. cloud_dog_logging-0.4.0/cloud_dog_logging/sinks/fan_out.py +65 -0
  51. cloud_dog_logging-0.4.0/cloud_dog_logging/sinks/file_sink.py +94 -0
  52. cloud_dog_logging-0.4.0/cloud_dog_logging/sinks/stdout_sink.py +56 -0
  53. cloud_dog_logging-0.4.0/cloud_dog_logging/tool_events.py +67 -0
  54. cloud_dog_logging-0.4.0/docs/ARCHITECTURE.md +16 -0
  55. cloud_dog_logging-0.4.0/docs/CONFIGURATION.md +16 -0
  56. cloud_dog_logging-0.4.0/docs/EXAMPLES.md +16 -0
  57. cloud_dog_logging-0.4.0/pyproject.toml +30 -0
  58. cloud_dog_logging-0.4.0/tests/__init__.py +2 -0
  59. cloud_dog_logging-0.4.0/tests/application/AT1.1_ServiceStartupPattern/test_service_startup.py +114 -0
  60. cloud_dog_logging-0.4.0/tests/application/AT1.2_AuditEventCoverage/test_audit_coverage.py +225 -0
  61. cloud_dog_logging-0.4.0/tests/application/AT1.3_HighVolumeLogging/test_high_volume.py +141 -0
  62. cloud_dog_logging-0.4.0/tests/application/AT1.4_DatabaseSinkPattern/test_db_sink_pattern.py +87 -0
  63. cloud_dog_logging-0.4.0/tests/application/AT1.5_SignedAuditChain/test_signed_audit.py +87 -0
  64. cloud_dog_logging-0.4.0/tests/conftest.py +153 -0
  65. cloud_dog_logging-0.4.0/tests/env-AT +3 -0
  66. cloud_dog_logging-0.4.0/tests/env-IT +3 -0
  67. cloud_dog_logging-0.4.0/tests/env-ST +3 -0
  68. cloud_dog_logging-0.4.0/tests/env-UT +3 -0
  69. cloud_dog_logging-0.4.0/tests/integration/IT1.1_FastAPIMiddleware/test_fastapi_middleware.py +126 -0
  70. cloud_dog_logging-0.4.0/tests/integration/IT1.2_CorrelationPropagation/test_correlation_propagation.py +106 -0
  71. cloud_dog_logging-0.4.0/tests/integration/IT1.3_RequestResponseLogging/test_request_logging.py +129 -0
  72. cloud_dog_logging-0.4.0/tests/quality/QT_PUBLISH_COMPLIANCE/__init__.py +2 -0
  73. cloud_dog_logging-0.4.0/tests/quality/QT_PUBLISH_COMPLIANCE/test_publish_compliance.py +58 -0
  74. cloud_dog_logging-0.4.0/tests/quality/__init__.py +2 -0
  75. cloud_dog_logging-0.4.0/tests/system/ST1.1_TwoStreamOutput/test_two_streams.py +137 -0
  76. cloud_dog_logging-0.4.0/tests/system/ST1.2_FileRotation/test_rotation.py +90 -0
  77. cloud_dog_logging-0.4.0/tests/system/ST1.3_AppendOnlyAudit/test_append_only.py +101 -0
  78. cloud_dog_logging-0.4.0/tests/system/ST1.4_LogLevelConfig/test_log_levels.py +69 -0
  79. cloud_dog_logging-0.4.0/tests/system/ST1.5_DualDestination/test_file_plus_stdout.py +66 -0
  80. cloud_dog_logging-0.4.0/tests/system/ST1.6_RotationNoLoss/test_rotation_no_loss.py +84 -0
  81. cloud_dog_logging-0.4.0/tests/system/ST_IntegrityVerifier/test_integrity_periodic.py +169 -0
  82. cloud_dog_logging-0.4.0/tests/system/ST_RotationEnforcement/test_rotation_enforcement.py +112 -0
  83. cloud_dog_logging-0.4.0/tests/unit/UT1.10_BackwardCompat/test_setup_logger.py +85 -0
  84. cloud_dog_logging-0.4.0/tests/unit/UT1.11_SecretScanGuard/test_secret_scan.py +127 -0
  85. cloud_dog_logging-0.4.0/tests/unit/UT1.12_AuditSinkInterface/test_audit_sink.py +61 -0
  86. cloud_dog_logging-0.4.0/tests/unit/UT1.13_FileSink/test_file_sink.py +65 -0
  87. cloud_dog_logging-0.4.0/tests/unit/UT1.14_StdoutSink/test_stdout_sink.py +50 -0
  88. cloud_dog_logging-0.4.0/tests/unit/UT1.15_FanOutSink/test_fan_out_sink.py +73 -0
  89. cloud_dog_logging-0.4.0/tests/unit/UT1.16_AuditSigning/test_signing.py +91 -0
  90. cloud_dog_logging-0.4.0/tests/unit/UT1.17_ToolEventHelper/test_tool_events.py +67 -0
  91. cloud_dog_logging-0.4.0/tests/unit/UT1.18_RedactionPresets/test_presets.py +48 -0
  92. cloud_dog_logging-0.4.0/tests/unit/UT1.19_LogSampling/test_sampling.py +46 -0
  93. cloud_dog_logging-0.4.0/tests/unit/UT1.1_JSONFormatter/test_json_formatter.py +144 -0
  94. cloud_dog_logging-0.4.0/tests/unit/UT1.20_AuditBatching/test_batching.py +87 -0
  95. cloud_dog_logging-0.4.0/tests/unit/UT1.21_ExceptionSerialisation/test_exception_format.py +81 -0
  96. cloud_dog_logging-0.4.0/tests/unit/UT1.2_TextFormatter/test_text_formatter.py +80 -0
  97. cloud_dog_logging-0.4.0/tests/unit/UT1.3_RedactionEngine/test_redaction.py +117 -0
  98. cloud_dog_logging-0.4.0/tests/unit/UT1.4_CorrelationID/test_correlation.py +113 -0
  99. cloud_dog_logging-0.4.0/tests/unit/UT1.5_AuditSchema/test_audit_schema.py +227 -0
  100. cloud_dog_logging-0.4.0/tests/unit/UT1.6_AuditLogger/test_audit_logger.py +169 -0
  101. cloud_dog_logging-0.4.0/tests/unit/UT1.7_AppLogger/test_app_logger.py +85 -0
  102. cloud_dog_logging-0.4.0/tests/unit/UT1.8_LoggerFactory/test_logger_factory.py +57 -0
  103. cloud_dog_logging-0.4.0/tests/unit/UT1.9_HealthReporter/test_health_reporter.py +89 -0
  104. cloud_dog_logging-0.4.0/tests/unit/UT_HandlerEnum/test_handler_enum.py +223 -0
  105. cloud_dog_logging-0.4.0/tests/unit/UT_IntegrityVerifier/test_integrity_verifier.py +158 -0
  106. cloud_dog_logging-0.4.0/tests/unit/UT_JSONFieldRegistry/test_json_field_registry.py +208 -0
  107. cloud_dog_logging-0.4.0/tests/unit/UT_LogRecordFactory/test_log_record_factory.py +204 -0
  108. cloud_dog_logging-0.4.0/tests/unit/UT_NIST_AU3/test_nist_au3_fields.py +136 -0
  109. cloud_dog_logging-0.4.0/working/W28A-316-INTEGRITY-FIX-REPORT.md +107 -0
@@ -0,0 +1,6 @@
1
+ schema-version: 1.0
2
+ project: platform-logging
3
+ canon-set: PACKAGE
4
+ canon-template-baseline: 1.0
5
+ conditional-docs: []
6
+ additional-docs: []
@@ -0,0 +1,16 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ coverage.xml
11
+ htmlcov/
12
+ working/
13
+ private/
14
+ archive/
15
+ logs/
16
+ *.db
@@ -0,0 +1,133 @@
1
+ # Agent Instruction — Fix cloud_dog_logging (v0.2.0)
2
+
3
+ **Package:** `cloud_dog_logging`
4
+ **Target version:** 0.2.0
5
+ **Date:** 2026-02-18 (updated with full gap analysis)
6
+ **Scope:** 7 new features (FR1.18–FR1.24) — **ALL DELIVERED AND VERIFIED**
7
+
8
+ ---
9
+
10
+ ## Status: ✅ COMPLETE
11
+
12
+ All 7 issues from cross-project impact assessment have been implemented, tested, and verified. This document is retained for reference and future maintenance.
13
+
14
+ **Verified on 2026-02-18:**
15
+ - 201 tests passed (IT env), 0 failed, 0 skipped
16
+ - Uplift scope: 33 passed (targeted v0.2.0 tests)
17
+ - Lint and format clean (`ruff check` + `ruff format --check`)
18
+ - Build produces `cloud_dog_logging-0.2.0.tar.gz` + `cloud_dog_logging-0.2.0-py3-none-any.whl`
19
+ - All 32 SA1 modules present
20
+ - All 35 test directories present and matching TESTS.md (21 UT + 6 ST + 3 IT + 5 AT)
21
+ - Zero config-delegation violations (no `os.environ`/`hvac`/Vault reads)
22
+
23
+ **Governing documents:**
24
+ 1. `platform-logging/REQUIREMENTS.md` (v0.2.0) — FR1.18–FR1.24
25
+ 2. `platform-logging/ARCHITECTURE.md` (v0.2.0) — CC1.11–CC1.17
26
+ 3. `platform-logging/TESTS.md` (v0.2.0) — UT1.12–UT1.21, AT1.4–AT1.5
27
+ 4. `packages/backend/AGENT-INSTRUCTION.md` — Integrity Warranty and Config Delegation — ZERO TOLERANCE (MANDATORY)
28
+
29
+ ---
30
+
31
+ ## Delivery Summary
32
+
33
+ ### Issue 1 — Pluggable Audit Sink ✅ DELIVERED
34
+
35
+ **FR:** FR1.18 | **Architecture:** CC1.11 | **Tests:** UT1.12–UT1.15, AT1.4
36
+
37
+ - `cloud_dog_logging/sinks/base.py` — `AuditSink` protocol (`emit`, `flush`, `close`) + `AuditRepository` protocol for DB sinks
38
+ - `cloud_dog_logging/sinks/file_sink.py` — `FileSink` JSONL file output
39
+ - `cloud_dog_logging/sinks/stdout_sink.py` — `StdoutSink` stdout output
40
+ - `cloud_dog_logging/sinks/db_sink.py` — `DatabaseSink` via `AuditRepository` protocol
41
+ - `cloud_dog_logging/sinks/fan_out.py` — `FanOutSink` multi-sink dispatch (one failure doesn't block others)
42
+ - `audit_logger.py` refactored to accept `sink` and `signer` parameters
43
+ - `__init__.py` → `_build_audit_sink()` wires sinks from `LogConfig`
44
+
45
+ ---
46
+
47
+ ### Issue 2 — Audit Signing Hooks ✅ DELIVERED
48
+
49
+ **FR:** FR1.19 | **Architecture:** CC1.12 | **Tests:** UT1.16, AT1.5
50
+
51
+ - `cloud_dog_logging/signing.py` — `AuditSigner` protocol + `HMACSigner` (HMAC-SHA256 with hash chaining)
52
+ - `pre_persist`: adds `_signature` and `_prev_signature` to event details
53
+ - `post_persist`: updates chain with latest signature
54
+ - Integrated into `AuditLogger` via `signer` parameter; `_build_signer()` in `__init__.py`
55
+
56
+ ---
57
+
58
+ ### Issue 3 — Tool Event Helper ✅ DELIVERED
59
+
60
+ **FR:** FR1.20 | **Architecture:** CC1.13 | **Tests:** UT1.17
61
+
62
+ - `cloud_dog_logging/tool_events.py` — `log_tool_event(tool, profile, duration_ms, paths, outcome, **details)`
63
+ - Generates `AuditEvent` with `event_type="tool_call"`, auto-attaches correlation ID and service name
64
+ - Exported from `__init__.py`
65
+
66
+ ---
67
+
68
+ ### Issue 4 — Redaction Presets ✅ DELIVERED
69
+
70
+ **FR:** FR1.21 | **Architecture:** CC1.14 | **Tests:** UT1.18
71
+
72
+ - `cloud_dog_logging/presets.py` — `RedactionPreset` frozen dataclass, `BUILTIN_PRESETS` dict (`default` + `file_tools`), `load_presets(config)` with config-driven composition
73
+ - `RedactionEngine` accepts `presets` parameter
74
+ - `setup_logging()` resolves presets from config via `_resolve_redaction_presets()`
75
+
76
+ ---
77
+
78
+ ### Issue 5 — Log Sampling ✅ DELIVERED
79
+
80
+ **FR:** FR1.22 | **Architecture:** CC1.15 | **Tests:** UT1.19
81
+
82
+ - `cloud_dog_logging/sampling.py` — `SamplingFilter(logging.Filter)` with per-logger rates, hierarchical name lookup, `sampled_out_count` metric
83
+ - WARNING+ always passes; audit events unaffected
84
+ - Wired into `setup_logging()` via `LogConfig.sampling_rates`
85
+
86
+ ---
87
+
88
+ ### Issue 6 — Audit Event Batching ✅ DELIVERED
89
+
90
+ **FR:** FR1.23 | **Architecture:** CC1.16 | **Tests:** UT1.20
91
+
92
+ - `cloud_dog_logging/batching.py` — `BatchingSink` wrapping any `AuditSink` with configurable `batch_size` (default 100) and `flush_interval_s` (default 5.0)
93
+ - Thread-safe with `threading.Lock`; ordering preserved; flush on batch full/interval/close
94
+ - Supports `emit_batch()` on underlying sink if available
95
+
96
+ ---
97
+
98
+ ### Issue 7 — Structured Exception Logging ✅ DELIVERED
99
+
100
+ **FR:** FR1.24 | **Architecture:** CC1.17 | **Tests:** UT1.21
101
+
102
+ - `cloud_dog_logging/exceptions.py` — `format_exception(exc)` returning `type`, `message`, `stack_hash` (SHA-256), `traceback` (list of frame strings)
103
+ - Stable `stack_hash` enables deduplication across identical exceptions
104
+ - Exported from `__init__.py`
105
+
106
+ ---
107
+
108
+ ## Public API Exports
109
+
110
+ All new APIs exported from `cloud_dog_logging/__init__.py`:
111
+ - `log_tool_event`, `format_exception`
112
+ - `AuditSink`, `FileSink`, `StdoutSink`, `DatabaseSink`, `FanOutSink`
113
+ - `BatchingSink`, `HMACSigner`
114
+ - `RedactionPreset`, `BUILTIN_PRESETS`, `load_presets`
115
+ - `SamplingFilter`
116
+
117
+ ---
118
+
119
+ ## Verification — Full Suite
120
+
121
+ ```bash
122
+ pytest tests --env tests/env-IT -q
123
+ ruff check cloud_dog_logging tests
124
+ ruff format --check cloud_dog_logging tests
125
+ python -m build --no-isolation
126
+ find cloud_dog_logging -name '*.py' -not -path '*__pycache__*' | sort
127
+ ```
128
+
129
+ ## pyproject.toml version
130
+
131
+ ```toml
132
+ version = "0.2.0"
133
+ ```
@@ -0,0 +1,475 @@
1
+ # platform-logging — Architecture
2
+
3
+ **Package:** `cloud_dog_logging`
4
+ **Version:** 0.3.0
5
+ **Standard:** PS-40 (Logging & Observability)
6
+ **Status:** Implemented
7
+
8
+ ---
9
+
10
+ ## OV1 — Overview
11
+
12
+ `cloud_dog_logging` is a drop-in Python library that implements the PS-40 logging and observability standard. It provides two mandatory log streams (audit + application), structured JSON output, correlation ID propagation, secret redaction, and configurable rotation — all behind a simple factory interface.
13
+
14
+ ### Design Goals
15
+
16
+ - **Single implementation** of the two-stream logging pattern — no per-project reimplementation.
17
+ - **Zero external dependencies** for core functionality (stdlib `logging` only).
18
+ - **Backward compatible** with existing `setup_logger()` patterns in notification-agent / expert-agent.
19
+ - **Framework-optional**: core library has no web framework dependency; FastAPI middleware is optional.
20
+ - **Async-safe**: compatible with asyncio event loops.
21
+
22
+ ---
23
+
24
+ ## SA1 — Module Layout
25
+
26
+ ```
27
+ cloud_dog_logging/
28
+ __init__.py # Public API: get_logger, get_audit_logger, setup_logger
29
+ config.py # Log configuration from platform config (PS-80)
30
+ app_logger.py # Application logger (structured JSON, levels)
31
+ audit_logger.py # Audit logger (append-only, typed events)
32
+ audit_schema.py # Audit event schema / models
33
+ correlation.py # Correlation ID context (contextvars)
34
+ redaction.py # Secret + PII redaction engine
35
+ formatters/
36
+ __init__.py
37
+ json_formatter.py # Structured JSON Lines formatter
38
+ text_formatter.py # Human-readable formatter (dev mode)
39
+ handlers/
40
+ __init__.py
41
+ rotating_file.py # Size + time-based rotating file handler
42
+ stdout_handler.py # Stdout/stderr handler (containers)
43
+ dual_handler.py # File + stdout simultaneously
44
+ middleware/
45
+ __init__.py
46
+ fastapi.py # FastAPI request logging + correlation ID middleware
47
+ health/
48
+ __init__.py
49
+ reporter.py # Log file size, rotation status, audit event count
50
+ compat.py # Backward-compatible setup_logger() function
51
+ errors.py # Logging-specific exceptions
52
+ sinks/
53
+ __init__.py
54
+ base.py # AuditSink protocol (FR1.18)
55
+ file_sink.py # FileSink — JSONL file output
56
+ stdout_sink.py # StdoutSink — stdout output
57
+ db_sink.py # DatabaseSink — DB table output (optional)
58
+ fan_out.py # FanOutSink — multiple sinks simultaneously
59
+ signing.py # Audit signing hooks (FR1.19)
60
+ tool_events.py # log_tool_event() helper (FR1.20)
61
+ presets.py # Redaction presets (FR1.21)
62
+ sampling.py # Log sampling filter (FR1.22)
63
+ batching.py # Audit event batching (FR1.23)
64
+ exceptions.py # Structured exception serialisation (FR1.24)
65
+ event_catalogue.py # Optional event catalogue validator (AU-2/AU-6)
66
+ integrity.py # Audit integrity verifier (FR1.25/FR1.26)
67
+ ```
68
+
69
+ ---
70
+
71
+ ## SA2 — Component Diagram
72
+
73
+ ```
74
+ ┌──────────────────────────────────────────────────────────────────┐
75
+ │ Service (FastAPI / CLI) │
76
+ │ │
77
+ │ middleware/fastapi.py ──→ inject correlation_id │
78
+ │ │ log request/response │
79
+ │ ▼ │
80
+ │ ┌──────────────┐ ┌──────────────┐ │
81
+ │ │ get_logger() │ │ get_audit_ │ │
82
+ │ │ → app_logger │ │ logger() │ │
83
+ │ │ │ │ → audit_ │ │
84
+ │ │ │ │ logger │ │
85
+ │ └──────┬───────┘ └──────┬───────┘ │
86
+ │ │ │ │
87
+ │ │ redaction.py ◄────────┤ │
88
+ │ │ (applied to both) │ │
89
+ │ │ │ │
90
+ │ ▼ ▼ │
91
+ │ ┌──────────────┐ ┌──────────────┐ │
92
+ │ │ formatters/ │ │ formatters/ │ │
93
+ │ │ json or text │ │ json only │ │
94
+ │ └──────┬───────┘ └──────┬───────┘ │
95
+ │ │ │ │
96
+ │ ▼ ▼ │
97
+ │ ┌──────────────┐ ┌──────────────┐ │
98
+ │ │ handlers/ │ │ handlers/ │ │
99
+ │ │ rotating_file│ │ rotating_file│ │
100
+ │ │ + stdout │ │ (append-only)│ │
101
+ │ └──────────────┘ └──────────────┘ │
102
+ │ │ │ │
103
+ │ ▼ ▼ │
104
+ │ logs/app.log logs/audit.log.jsonl │
105
+ │ (or stdout) (or stdout) │
106
+ └──────────────────────────────────────────────────────────────────┘
107
+
108
+ └──→ correlation.py (contextvars: correlation_id per request)
109
+ ```
110
+
111
+ ---
112
+
113
+ ## CC1 — Core Components
114
+
115
+ ### CC1.1 Application Logger (`app_logger.py`)
116
+
117
+ Standard Python logger with structured JSON output:
118
+
119
+ ```python
120
+ class AppLogger:
121
+ """Structured application logger."""
122
+
123
+ def debug(self, msg, **extra): ...
124
+ def info(self, msg, **extra): ...
125
+ def warning(self, msg, **extra): ...
126
+ def error(self, msg, **extra): ...
127
+ def critical(self, msg, **extra): ...
128
+ def exception(self, msg, **extra): ...
129
+ ```
130
+
131
+ - All entries include: `timestamp`, `level`, `logger`, `message`, `correlation_id`, `service`, `extra`.
132
+ - Extra fields are redacted before output.
133
+ - Built on stdlib `logging.Logger` — compatible with existing Python logging ecosystem.
134
+
135
+ ### CC1.2 Audit Logger (`audit_logger.py`)
136
+
137
+ Typed audit event logger with mandatory schema:
138
+
139
+ ```python
140
+ class AuditLogger:
141
+ """Append-only audit event logger."""
142
+
143
+ def emit(self, event: AuditEvent) -> None:
144
+ """Emit a raw audit event."""
145
+
146
+ def log_login(self, actor: Actor, outcome: str, **details) -> None: ...
147
+ def log_crud(self, actor: Actor, action: str, target: Target, outcome: str, **details) -> None: ...
148
+ def log_config_change(self, actor: Actor, diff_summary: dict, outcome: str, **details) -> None: ...
149
+ def log_tool_call(self, actor: Actor, tool: str, params: dict, outcome: str, duration_ms: int, **details) -> None: ...
150
+ def log_security(self, actor: Actor, action: str, target: Target, outcome: str, **details) -> None: ...
151
+ ```
152
+
153
+ - All events validated against `AuditEvent` schema before writing.
154
+ - Details field scanned for secrets and redacted.
155
+ - Append-only: handler configured to not truncate/overwrite.
156
+
157
+ ### CC1.3 Audit Event Schema (`audit_schema.py`)
158
+
159
+ ```python
160
+ @dataclass
161
+ class Actor:
162
+ type: str # "user" | "service" | "system"
163
+ id: str # Stable user/service identifier
164
+ roles: list[str] | None = None
165
+
166
+ @dataclass
167
+ class Target:
168
+ type: str # "user" | "session" | "config" | "api_key" | etc.
169
+ id: str # Target entity identifier
170
+
171
+ @dataclass
172
+ class AuditEvent:
173
+ timestamp: str # ISO 8601 UTC
174
+ event_type: str # e.g., "user.login", "config.reload"
175
+ actor: Actor
176
+ action: str # "create" | "update" | "delete" | "login" | etc.
177
+ outcome: str # "success" | "failure" | "error"
178
+ correlation_id: str
179
+ service: str
180
+ target: Target | None = None
181
+ details: dict | None = None
182
+ duration_ms: int | None = None
183
+ ```
184
+
185
+ ### CC1.4 Correlation ID (`correlation.py`)
186
+
187
+ ```python
188
+ # Context-local correlation ID using contextvars
189
+ correlation_id_var: ContextVar[str]
190
+
191
+ def get_correlation_id() -> str:
192
+ """Get current correlation ID (generates new if none set)."""
193
+
194
+ def set_correlation_id(cid: str) -> None:
195
+ """Set correlation ID for current context."""
196
+
197
+ def correlation_id_middleware(header_name: str = "X-Request-Id"):
198
+ """Extract or generate correlation ID from request header."""
199
+ ```
200
+
201
+ - `contextvars.ContextVar` ensures async-safety.
202
+ - All loggers automatically read from context.
203
+
204
+ ### CC1.5 Redaction Engine (`redaction.py`)
205
+
206
+ ```python
207
+ class RedactionEngine:
208
+ """Redact secrets and PII from log data."""
209
+
210
+ def __init__(self, patterns: list[str] | None = None): ...
211
+ def redact(self, data: dict) -> dict: ...
212
+ def redact_string(self, value: str) -> str: ...
213
+ ```
214
+
215
+ - Default patterns: keys containing `secret`, `password`, `key`, `token`, `credential`, `api_key`.
216
+ - Configurable additional patterns per project.
217
+ - Recursive dict/list scanning.
218
+ - Values replaced with `***REDACTED***`.
219
+
220
+ ### CC1.6 JSON Formatter (`formatters/json_formatter.py`)
221
+
222
+ ```python
223
+ class JSONFormatter(logging.Formatter):
224
+ """Structured JSON Lines formatter for both log streams."""
225
+
226
+ def format(self, record: LogRecord) -> str: ...
227
+ ```
228
+
229
+ - One JSON object per line.
230
+ - Includes all required fields from FR1.3/FR1.4.
231
+ - Handles exceptions (serialises traceback as string).
232
+
233
+ ### CC1.7 Rotating File Handler (`handlers/rotating_file.py`)
234
+
235
+ ```python
236
+ class ConfigurableRotatingHandler(logging.Handler):
237
+ """Size + time-based rotation with retention."""
238
+
239
+ def __init__(
240
+ self,
241
+ filename: str,
242
+ max_bytes: int = 10_485_760, # 10MB
243
+ backup_count: int = 5,
244
+ when: str = "midnight", # time-based trigger
245
+ interval: int = 1,
246
+ ): ...
247
+ ```
248
+
249
+ - Combines `RotatingFileHandler` and `TimedRotatingFileHandler` behaviour.
250
+ - Configurable via platform config (`log.rotation.*`).
251
+ - Rotation MUST NOT lose log entries.
252
+
253
+ ### CC1.8 FastAPI Middleware (`middleware/fastapi.py`)
254
+
255
+ ```python
256
+ class LoggingMiddleware:
257
+ """FastAPI middleware for request logging and correlation ID."""
258
+
259
+ async def dispatch(self, request, call_next):
260
+ # 1. Extract or generate correlation ID
261
+ # 2. Set in contextvars
262
+ # 3. Log request start
263
+ # 4. Call next
264
+ # 5. Log request end (status, duration, client IP)
265
+ # 6. Add X-Request-Id to response headers
266
+ ```
267
+
268
+ ### CC1.9 Backward Compatibility (`compat.py`)
269
+
270
+ ```python
271
+ def setup_logger(
272
+ name: str,
273
+ log_file: str,
274
+ log_level: str = "INFO",
275
+ log_format: str = "json",
276
+ console: bool = True,
277
+ ) -> logging.Logger:
278
+ """Backward-compatible setup matching existing project patterns."""
279
+ ```
280
+
281
+ Drop-in replacement for the `setup_logger()` function used in notification-agent and expert-agent.
282
+
283
+ ### CC1.10 Health Reporter (`health/reporter.py`)
284
+
285
+ ```python
286
+ class LogHealthReporter:
287
+ """Observability data for log subsystem."""
288
+
289
+ def get_status(self) -> dict:
290
+ """Returns: file sizes, rotation status, audit event count, last audit timestamp."""
291
+ ```
292
+
293
+ ### CC1.11 Audit Sink Interface (`sinks/base.py`)
294
+
295
+ ```python
296
+ class AuditSink(Protocol):
297
+ def emit(self, event: AuditEvent) -> None: ...
298
+ def flush(self) -> None: ...
299
+ def close(self) -> None: ...
300
+ ```
301
+
302
+ Built-in implementations:
303
+ - `FileSink` — writes JSONL to file (existing behaviour, extracted).
304
+ - `StdoutSink` — writes to stdout.
305
+ - `DatabaseSink` — writes to DB table via repository protocol (optional dependency).
306
+ - `FanOutSink` — dispatches to multiple sinks simultaneously.
307
+
308
+ ### CC1.12 Audit Signing (`signing.py`)
309
+
310
+ ```python
311
+ class AuditSigner(Protocol):
312
+ def pre_persist(self, event: AuditEvent) -> AuditEvent: ...
313
+ def post_persist(self, event: AuditEvent) -> None: ...
314
+
315
+ class HMACSigner:
316
+ """HMAC-SHA256 signing for tamper-evident audit records."""
317
+ def __init__(self, secret_key: str): ...
318
+ ```
319
+
320
+ - Invoked by `AuditLogger` before/after sink emit.
321
+ - Disabled by default; enabled via config (`log.audit.signing.enabled`).
322
+
323
+ ### CC1.13 Tool Event Helper (`tool_events.py`)
324
+
325
+ ```python
326
+ def log_tool_event(
327
+ tool: str,
328
+ profile: str | None = None,
329
+ duration_ms: int | None = None,
330
+ paths: list[str] | None = None,
331
+ outcome: str = "success",
332
+ **details,
333
+ ) -> None:
334
+ """Convenience helper for MCP/tool audit events."""
335
+ ```
336
+
337
+ ### CC1.14 Redaction Presets (`presets.py`)
338
+
339
+ ```python
340
+ class RedactionPreset:
341
+ name: str
342
+ patterns: list[str]
343
+
344
+ BUILTIN_PRESETS: dict[str, RedactionPreset] = {
345
+ "default": RedactionPreset(name="default", patterns=[...]),
346
+ "file_tools": RedactionPreset(name="file_tools", patterns=[...]),
347
+ }
348
+
349
+ def load_presets(config: dict) -> list[RedactionPreset]:
350
+ """Load and compose redaction presets from config."""
351
+ ```
352
+
353
+ ### CC1.15 Log Sampling (`sampling.py`)
354
+
355
+ ```python
356
+ class SamplingFilter(logging.Filter):
357
+ """Per-logger sampling for high-volume DEBUG logs."""
358
+
359
+ def __init__(self, rates: dict[str, float]): ...
360
+ def filter(self, record: LogRecord) -> bool: ...
361
+ ```
362
+
363
+ - Only applies to DEBUG level; WARNING+ always passes.
364
+ - Counted metrics for sampled-out entries.
365
+
366
+ ### CC1.16 Audit Batching (`batching.py`)
367
+
368
+ ```python
369
+ class BatchingSink:
370
+ """Wraps a sink with batch flush semantics."""
371
+
372
+ def __init__(self, sink: AuditSink, batch_size: int = 100, flush_interval_s: float = 5.0): ...
373
+ def emit(self, event: AuditEvent) -> None: ...
374
+ def flush(self) -> None: ...
375
+ def close(self) -> None: ...
376
+ ```
377
+
378
+ - Flush on batch size reached, interval elapsed, or shutdown signal.
379
+ - Ordering preserved within batch.
380
+
381
+ ### CC1.17 Structured Exception Serialisation (`exceptions.py`)
382
+
383
+ ```python
384
+ def format_exception(exc: BaseException) -> dict:
385
+ """Serialise exception with type, message, stack_hash, traceback."""
386
+ ```
387
+
388
+ - `stack_hash` = SHA-256 of normalised traceback string (for dedup).
389
+ - Used by `AppLogger.exception()` and audit event details.
390
+
391
+ ### CC1.18 Audit Integrity Verifier (`integrity.py`)
392
+
393
+ ```python
394
+ class AuditIntegrityVerifier:
395
+ """Periodic hash verification for audit log files."""
396
+
397
+ def start(self) -> None: ...
398
+ def stop(self) -> None: ...
399
+ def compute_now(self, trigger: str = "manual") -> dict: ...
400
+ ```
401
+
402
+ - Computes `sha256` (default), `sha512`, or `crc32` hashes over full audit log content.
403
+ - Writes integrity records to both application logs and `logs/audit-integrity.log`.
404
+ - Emits records on `startup`, `periodic`, `rotation`, `manual`, and `shutdown`.
405
+
406
+ ---
407
+
408
+ ## DM1 — Data Model
409
+
410
+ No persistent database. Logs are file-based or stdout-based.
411
+
412
+ ### Log File Convention
413
+
414
+ ```
415
+ logs/
416
+ app.log # Application log (current)
417
+ app.log.1 # Rotated application logs
418
+ app.log.2
419
+ audit.log.jsonl # Audit log (current, append-only)
420
+ audit.log.jsonl.1 # Rotated audit logs
421
+ audit-integrity.log # Integrity verification JSONL records
422
+ ```
423
+
424
+ File paths configurable via platform config (`log.app_log`, `log.audit_log`).
425
+
426
+ ---
427
+
428
+ ## DP1 — Dependency Policy
429
+
430
+ | Dependency | Status | Notes |
431
+ |-----------|--------|-------|
432
+ | stdlib `logging` | Required | Core logging framework |
433
+ | `python-json-logger` | Optional | Enhanced JSON formatting (falls back to built-in) |
434
+
435
+ No web framework dependency. No database dependency. No external service dependency.
436
+
437
+ ---
438
+
439
+ ## SE1 — Security Architecture
440
+
441
+ - Secret redaction applied to all log output paths before writing.
442
+ - Audit log is append-only — handlers configured to not truncate.
443
+ - Correlation IDs contain no sensitive information (UUID or hex token).
444
+ - PII redaction configurable per project.
445
+ - Log files SHOULD have restricted filesystem permissions (configurable).
446
+
447
+ ---
448
+
449
+ ## Integration Pattern
450
+
451
+ Services consume the package as follows:
452
+
453
+ ```python
454
+ from cloud_dog_logging import get_logger, get_audit_logger, setup_logging
455
+ from cloud_dog_logging.audit_schema import Actor, Target
456
+
457
+ # At startup (once)
458
+ setup_logging(config) # Reads log.* from GlobalConfig
459
+
460
+ # In application code
461
+ logger = get_logger(__name__)
462
+ logger.info("Processing request", extra={"user_id": user.id})
463
+
464
+ # For security events
465
+ audit = get_audit_logger()
466
+ audit.log_login(
467
+ actor=Actor(type="user", id=str(user.id)),
468
+ outcome="success",
469
+ ip=request.client.host,
470
+ )
471
+
472
+ # For FastAPI
473
+ from cloud_dog_logging.middleware.fastapi import LoggingMiddleware
474
+ app.add_middleware(LoggingMiddleware)
475
+ ```