road24-artifacthub 0.1.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 (64) hide show
  1. road24_artifacthub-0.1.0/.claude/CLAUDE.md +151 -0
  2. road24_artifacthub-0.1.0/.claude/agents/engineer.md +256 -0
  3. road24_artifacthub-0.1.0/.claude/agents/tester.md +495 -0
  4. road24_artifacthub-0.1.0/.gitignore +18 -0
  5. road24_artifacthub-0.1.0/.hooks/check-commit-msg.sh +16 -0
  6. road24_artifacthub-0.1.0/.pre-commit-config.yaml +49 -0
  7. road24_artifacthub-0.1.0/Makefile +37 -0
  8. road24_artifacthub-0.1.0/PKG-INFO +122 -0
  9. road24_artifacthub-0.1.0/README.md +86 -0
  10. road24_artifacthub-0.1.0/commands/__init__.py +0 -0
  11. road24_artifacthub-0.1.0/commands/test_logs_db.py +44 -0
  12. road24_artifacthub-0.1.0/commands/test_logs_exceptions.py +59 -0
  13. road24_artifacthub-0.1.0/commands/test_logs_http_input.py +106 -0
  14. road24_artifacthub-0.1.0/commands/test_logs_http_output.py +35 -0
  15. road24_artifacthub-0.1.0/commands/test_logs_redis.py +34 -0
  16. road24_artifacthub-0.1.0/commands/test_metrics_http.py +54 -0
  17. road24_artifacthub-0.1.0/examples/__init__.py +0 -0
  18. road24_artifacthub-0.1.0/examples/core/__init__.py +0 -0
  19. road24_artifacthub-0.1.0/examples/core/database/__init__.py +0 -0
  20. road24_artifacthub-0.1.0/examples/core/database/config.py +39 -0
  21. road24_artifacthub-0.1.0/examples/core/database/mixins.py +37 -0
  22. road24_artifacthub-0.1.0/examples/core/http.py +53 -0
  23. road24_artifacthub-0.1.0/examples/core/redis.py +80 -0
  24. road24_artifacthub-0.1.0/examples/core/road24.py +26 -0
  25. road24_artifacthub-0.1.0/examples/core/settings.py +57 -0
  26. road24_artifacthub-0.1.0/examples/core/utils.py +8 -0
  27. road24_artifacthub-0.1.0/examples/src/__init__.py +0 -0
  28. road24_artifacthub-0.1.0/examples/src/main.py +33 -0
  29. road24_artifacthub-0.1.0/main.py +6 -0
  30. road24_artifacthub-0.1.0/pyproject.toml +56 -0
  31. road24_artifacthub-0.1.0/road24_sdk/__init__.py +65 -0
  32. road24_artifacthub-0.1.0/road24_sdk/_formatter.py +213 -0
  33. road24_artifacthub-0.1.0/road24_sdk/_sanitizer.py +61 -0
  34. road24_artifacthub-0.1.0/road24_sdk/_schemas.py +117 -0
  35. road24_artifacthub-0.1.0/road24_sdk/_types.py +54 -0
  36. road24_artifacthub-0.1.0/road24_sdk/integrations/__init__.py +13 -0
  37. road24_artifacthub-0.1.0/road24_sdk/integrations/_base.py +19 -0
  38. road24_artifacthub-0.1.0/road24_sdk/integrations/fastapi.py +258 -0
  39. road24_artifacthub-0.1.0/road24_sdk/integrations/httpx.py +120 -0
  40. road24_artifacthub-0.1.0/road24_sdk/integrations/redis.py +233 -0
  41. road24_artifacthub-0.1.0/road24_sdk/integrations/sqlalchemy.py +175 -0
  42. road24_artifacthub-0.1.0/road24_sdk/metrics/__init__.py +9 -0
  43. road24_artifacthub-0.1.0/road24_sdk/metrics/db.py +29 -0
  44. road24_artifacthub-0.1.0/road24_sdk/metrics/http.py +33 -0
  45. road24_artifacthub-0.1.0/road24_sdk/metrics/redis.py +29 -0
  46. road24_artifacthub-0.1.0/tests/__init__.py +0 -0
  47. road24_artifacthub-0.1.0/tests/conftest.py +170 -0
  48. road24_artifacthub-0.1.0/tests/test_data_classes.py +81 -0
  49. road24_artifacthub-0.1.0/tests/test_formatter.py +446 -0
  50. road24_artifacthub-0.1.0/tests/test_init.py +85 -0
  51. road24_artifacthub-0.1.0/tests/test_integrations/__init__.py +0 -0
  52. road24_artifacthub-0.1.0/tests/test_integrations/test_base.py +50 -0
  53. road24_artifacthub-0.1.0/tests/test_integrations/test_fastapi.py +803 -0
  54. road24_artifacthub-0.1.0/tests/test_integrations/test_httpx.py +512 -0
  55. road24_artifacthub-0.1.0/tests/test_integrations/test_redis.py +395 -0
  56. road24_artifacthub-0.1.0/tests/test_integrations/test_sqlalchemy.py +374 -0
  57. road24_artifacthub-0.1.0/tests/test_metrics/__init__.py +0 -0
  58. road24_artifacthub-0.1.0/tests/test_metrics/test_db.py +183 -0
  59. road24_artifacthub-0.1.0/tests/test_metrics/test_http.py +199 -0
  60. road24_artifacthub-0.1.0/tests/test_metrics/test_redis.py +201 -0
  61. road24_artifacthub-0.1.0/tests/test_sanitizer.py +325 -0
  62. road24_artifacthub-0.1.0/tests/test_schemas.py +385 -0
  63. road24_artifacthub-0.1.0/tests/test_types.py +411 -0
  64. road24_artifacthub-0.1.0/uv.lock +1016 -0
@@ -0,0 +1,151 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ **road24-artifacthub** is a shared Python SDK providing logging and metrics utilities for Road24 microservices. It follows a Sentry SDK-like pattern with framework-specific integrations.
8
+
9
+ **Stack:** Python 3.12+, dataclasses, prometheus_client
10
+
11
+ **Dependencies:**
12
+ - `prometheus-client` - For Prometheus metrics
13
+ - `httpx` - For HTTPX client integration
14
+ - `redis` - For Redis client integration
15
+ - `sqlalchemy` - For SQLAlchemy database integration
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Core library
21
+ pip install road24-artifacthub
22
+
23
+ # Development
24
+ pip install road24-artifacthub[dev]
25
+ ```
26
+
27
+ ## Commands
28
+
29
+ ```bash
30
+ # Testing
31
+ pytest # Run all tests
32
+ pytest -v # Verbose output
33
+ pytest tests/ # Test specific module
34
+ pytest --cov=road24_sdk # Coverage report
35
+
36
+ # Code Quality
37
+ ruff check . # Linting
38
+ ruff format . # Formatting
39
+ ```
40
+
41
+ ## Architecture
42
+
43
+ ### Module Structure
44
+
45
+ ```
46
+ road24_sdk/ # Main package
47
+ ├── __init__.py # Public API: init(), configure(), enums
48
+ ├── _types.py # ArtifactHubConfig + StrEnum definitions (internal)
49
+ ├── _schemas.py # Dataclass schemas for log attributes (internal)
50
+ ├── _formatter.py # LogFormatter, setup_logging(), trace context, ExceptionLogger (internal)
51
+ ├── _sanitizer.py # Body sanitization utilities (internal)
52
+ ├── metrics/ # Prometheus metrics utilities
53
+ │ ├── __init__.py # Public exports
54
+ │ ├── http.py # HTTP request metrics
55
+ │ ├── db.py # Database query metrics
56
+ │ └── redis.py # Redis command metrics
57
+ └── integrations/ # Framework-specific integrations (logging + metrics)
58
+ ├── __init__.py # Exports all integrations + Integration base
59
+ ├── _base.py # Integration ABC with setup_once() pattern
60
+ ├── fastapi.py # FastApiLoggingIntegration + HttpInputLogger
61
+ ├── httpx.py # HttpxLoggingIntegration + HttpOutputLogger
62
+ ├── sqlalchemy.py # SqlalchemyLoggingIntegration + DbLogger
63
+ └── redis.py # RedisLoggingIntegration + RedisLogger + LoggedRedis
64
+ ```
65
+
66
+ ### Key Patterns
67
+
68
+ **SDK-like Initialization:** Uses `init()` function similar to Sentry SDK with `integrations=[]` for auto-instrumentation:
69
+ ```python
70
+ import road24_sdk
71
+ from road24_sdk.integrations.httpx import HttpxLoggingIntegration
72
+ from road24_sdk.integrations.redis import RedisLoggingIntegration
73
+
74
+ road24_sdk.init(
75
+ service_name="my-service",
76
+ log_level="INFO",
77
+ integrations=[
78
+ HttpxLoggingIntegration(),
79
+ RedisLoggingIntegration(),
80
+ ],
81
+ )
82
+ ```
83
+
84
+ **Integration Pattern:** All integrations inherit from `Integration` ABC and implement `setup_once()` for class-level patching (called via `init()`) and `.setup(client)` for instance-level patching.
85
+ - `setup_once()` patches at class level so all new instances are auto-instrumented.
86
+ - `.setup(client)` patches a specific client instance (backwards compatible).
87
+ - `FastApiLoggingIntegration` requires `.setup(app)` since it needs the app instance.
88
+
89
+ **When adding new integrations**, implement both `setup_once()` (class-level patching) and `.setup(client)` (instance-level patching). Inherit from `Integration` ABC.
90
+
91
+ **Trace Context Propagation:** Uses `ContextVar` for thread-safe trace ID propagation across async operations.
92
+
93
+ **Metrics Recording:** All operations record both duration (Histogram) and count (Counter) with normalized labels.
94
+
95
+ ## Code Style Requirements
96
+
97
+ - Full type hints on all functions (Python 3.12+ syntax)
98
+ - Use `StrEnum` for all enum definitions
99
+ - Use `ContextVar` for request-scoped state (not global variables)
100
+ - Use dataclasses with `slots=True` for schemas
101
+ - Guard clauses (early returns) over nested conditionals
102
+ - Async/await for all async utilities
103
+ - No comments except for complex logic
104
+ - Keep functions under 20 lines
105
+ - Use `TYPE_CHECKING` for optional dependencies
106
+
107
+ ## Consumer Integration
108
+
109
+ Pass integrations to `init()` for auto-instrumentation. All new client instances are automatically patched.
110
+
111
+ ```python
112
+ import road24_sdk
113
+ from road24_sdk.integrations.fastapi import FastApiLoggingIntegration
114
+ from road24_sdk.integrations.httpx import HttpxLoggingIntegration
115
+ from road24_sdk.integrations.sqlalchemy import SqlalchemyLoggingIntegration
116
+ from road24_sdk.integrations.redis import RedisLoggingIntegration
117
+
118
+ # Initialize with integrations — auto-instruments all new client instances
119
+ road24_sdk.init(
120
+ service_name="my-service",
121
+ log_level="INFO",
122
+ debug=False,
123
+ integrations=[
124
+ FastApiLoggingIntegration(),
125
+ HttpxLoggingIntegration(),
126
+ SqlalchemyLoggingIntegration(),
127
+ RedisLoggingIntegration(),
128
+ ],
129
+ )
130
+
131
+ # FastAPI still requires .setup(app) since it needs the app instance
132
+ app = FastAPI()
133
+ FastApiLoggingIntegration().setup(app)
134
+
135
+ # All other clients are auto-instrumented — no .setup() needed
136
+ client = AsyncClient(timeout=Timeout(25.0)) # already instrumented
137
+ engine = create_async_engine(DATABASE_URL) # already instrumented
138
+ redis = Redis.from_url(REDIS_URL) # already instrumented
139
+ ```
140
+
141
+ The `.setup(client)` method still works for per-instance patching (backwards compatible).
142
+
143
+ ## Testing Guidelines
144
+
145
+ - All tests must be async (`@pytest.mark.asyncio`)
146
+ - Mock all external dependencies (AsyncMock for async, Mock for sync)
147
+ - Use fixtures for test data in `tests/conftest.py`
148
+ - Use `@pytest.mark.parametrize` with dataclasses for multiple scenarios
149
+ - Follow AAA pattern (Arrange-Act-Assert)
150
+ - Target >90% coverage
151
+ - Test file structure mirrors source structure
@@ -0,0 +1,256 @@
1
+ ---
2
+ name: engineer
3
+ description: Senior Python developer for road24-artifacthub shared library. Provides logging and metrics utilities for microservices. Framework-agnostic. MUST run tests after changes.
4
+ tools: Read, Edit, Write, Bash, Grep, Glob, Task
5
+ model: opus
6
+ ---
7
+
8
+ ## Critical Rules
9
+
10
+ 1. **ALWAYS** follow SOLID principles and existing patterns
11
+ 2. **ALWAYS** run tests after changes: `pytest`
12
+ 3. **ALWAYS** use full type hints (Python 3.12+)
13
+ 4. **ALWAYS** use async/await for async utilities
14
+ 5. **ALWAYS** use structured logging patterns
15
+ 6. **ALWAYS** maintain backwards compatibility for consumer services
16
+ 7. **ALWAYS** use `TYPE_CHECKING` for optional dependencies (httpx, redis, sqlalchemy)
17
+ 8. **NEVER** write comments except for complex logic
18
+ 9. **NEVER** add unrequested features (YAGNI)
19
+
20
+ ## Documentation Reference
21
+
22
+ **IMPORTANT:** For comprehensive project documentation, architecture details, and complete guidelines, refer to:
23
+ - **`.claude/CLAUDE.md`** - Main project guide with stack details, architecture, and coding standards
24
+
25
+ This agent guide is a condensed development reference. Always consult CLAUDE.md for authoritative project information.
26
+
27
+ ## Project: road24-artifacthub
28
+
29
+ Shared Python SDK providing logging and metrics utilities for Road24 microservices. Follows a Sentry SDK-like pattern with framework-specific integrations.
30
+
31
+ **Stack:** Python 3.12+, dataclasses, prometheus_client
32
+
33
+ **Optional:** httpx, redis, sqlalchemy
34
+
35
+ ## Library Structure
36
+
37
+ ```
38
+ road24_sdk/ # Main package
39
+ ├── __init__.py # Public API: init(), configure(), enums
40
+ ├── _types.py # ArtifactHubConfig + StrEnum definitions (internal)
41
+ ├── _schemas.py # Dataclass schemas for log attributes (internal)
42
+ ├── _formatter.py # LogFormatter, setup_logging(), trace context, ExceptionLogger (internal)
43
+ ├── _sanitizer.py # Body sanitization utilities (internal)
44
+ ├── metrics/ # Prometheus metrics utilities
45
+ │ ├── __init__.py # Public exports
46
+ │ ├── http.py # HTTP request metrics
47
+ │ ├── db.py # Database query metrics
48
+ │ └── redis.py # Redis command metrics
49
+ └── integrations/ # Framework-specific integrations (logging + metrics)
50
+ ├── __init__.py # Exports all integrations + Integration base
51
+ ├── _base.py # Integration ABC with setup_once() pattern
52
+ ├── fastapi.py # FastApiLoggingIntegration + HttpInputLogger
53
+ ├── httpx.py # HttpxLoggingIntegration + HttpOutputLogger
54
+ ├── sqlalchemy.py # SqlalchemyLoggingIntegration + DbLogger
55
+ └── redis.py # RedisLoggingIntegration + RedisLogger
56
+ ```
57
+
58
+ ## Integration Pattern
59
+
60
+ All integrations inherit from `Integration` ABC and support two patching modes:
61
+ - `setup_once()` — class-level patching, called automatically by `init(integrations=[...])`
62
+ - `.setup(client)` — instance-level patching (backwards compatible)
63
+
64
+ ```python
65
+ # Auto-instrumentation via init()
66
+ road24_sdk.init(
67
+ service_name="my-service",
68
+ integrations=[HttpxLoggingIntegration()],
69
+ )
70
+ # All new AsyncClient instances are auto-patched
71
+
72
+ # Per-instance patching (still works)
73
+ client = AsyncClient(timeout=Timeout(25.0))
74
+ HttpxLoggingIntegration().setup(client)
75
+ ```
76
+
77
+ When adding new integrations, inherit from `Integration` and implement both `setup_once()` and `.setup(client)`.
78
+
79
+ ## Key Components
80
+
81
+ **LogFormatter** (`_formatter.py`):
82
+ - JSON output with structured format
83
+ - Trace ID context propagation via ContextVar
84
+ - Automatic exception formatting
85
+
86
+ **Integrations** (`integrations/*.py`):
87
+ - Each integration has a Logger class (e.g., `DbLogger`, `RedisLogger`)
88
+ - Each integration has a `*LoggingIntegration` class with `.setup(client)` method
89
+ - Logger classes handle: operation extraction, table/key extraction, metrics recording, structured logging
90
+ - `.setup()` monkey-patches client methods to add timing, logging, and metrics
91
+
92
+ **Metrics** (`metrics/*.py`):
93
+ - Prometheus Histogram for durations
94
+ - Prometheus Counter for totals
95
+ - Labeled metrics (operation, table/key/url)
96
+
97
+ ## Consumer Integration
98
+
99
+ ```python
100
+ import road24_sdk
101
+ from road24_sdk.integrations.fastapi import FastApiLoggingIntegration
102
+ from road24_sdk.integrations.httpx import HttpxLoggingIntegration
103
+ from road24_sdk.integrations.sqlalchemy import SqlalchemyLoggingIntegration
104
+ from road24_sdk.integrations.redis import RedisLoggingIntegration
105
+
106
+ road24_sdk.init(
107
+ service_name="my-service",
108
+ log_level="INFO",
109
+ integrations=[
110
+ FastApiLoggingIntegration(),
111
+ HttpxLoggingIntegration(),
112
+ SqlalchemyLoggingIntegration(),
113
+ RedisLoggingIntegration(),
114
+ ],
115
+ )
116
+
117
+ # FastAPI still requires .setup(app)
118
+ FastApiLoggingIntegration().setup(app)
119
+
120
+ # Other clients are auto-instrumented — no .setup() needed
121
+ ```
122
+
123
+ ## Workflow
124
+
125
+ 1. **Read** existing code first (`Read` tool)
126
+ 2. **Search** patterns (`Grep`/`Glob`)
127
+ 3. **Implement** following existing patterns
128
+ 4. **Test** changes: `pytest`
129
+ 5. **Check** quality: `ruff check .`
130
+
131
+ ## Code Style (Mandatory)
132
+
133
+ **Type Hints:**
134
+ ```python
135
+ def record_db_query(
136
+ operation: DbOperation,
137
+ table: str,
138
+ duration_seconds: float,
139
+ ) -> None:
140
+ ...
141
+ ```
142
+
143
+ **Optional Dependencies with TYPE_CHECKING:**
144
+ ```python
145
+ from typing import TYPE_CHECKING
146
+
147
+ if TYPE_CHECKING:
148
+ from redis.asyncio import Redis
149
+
150
+ def setup(self, client: "Redis") -> None:
151
+ ...
152
+ ```
153
+
154
+ **Guard Clauses (Early Returns):**
155
+ ```python
156
+ def extract_operation(self, statement: str) -> DbOperation:
157
+ statement_upper = statement.strip().upper()
158
+ if statement_upper.startswith("SELECT"):
159
+ return DbOperation.SELECT
160
+ if statement_upper.startswith("INSERT"):
161
+ return DbOperation.INSERT
162
+ return DbOperation.OTHER
163
+ ```
164
+
165
+ **Dataclasses with slots:**
166
+ ```python
167
+ @dataclass(slots=True)
168
+ class DbAttributes:
169
+ operation: DbOperation
170
+ table: str
171
+ duration_seconds: float
172
+ statement: str = ""
173
+ ```
174
+
175
+ **StrEnum for all enums:**
176
+ ```python
177
+ class DbOperation(StrEnum):
178
+ SELECT = "select"
179
+ INSERT = "insert"
180
+ OTHER = "other"
181
+ ```
182
+
183
+ ## Naming Conventions
184
+
185
+ - **Loggers**: `{Domain}Logger` (e.g., `DbLogger`, `RedisLogger`)
186
+ - **Integrations**: `{Framework}LoggingIntegration` (e.g., `SqlalchemyLoggingIntegration`)
187
+ - **Schemas**: `{Domain}Attributes` (e.g., `DbAttributes`, `RedisAttributes`)
188
+ - **Metrics**: `UPPER_SNAKE_CASE` (e.g., `DB_QUERY_DURATION`)
189
+ - **Enums**: `{Domain}Operation` using `StrEnum`
190
+ - **Functions**: `snake_case` (e.g., `record_db_query`)
191
+ - **Private**: `_prefix`
192
+
193
+ ## Commands
194
+
195
+ ```bash
196
+ pytest # Run all tests
197
+ pytest -v # Verbose output
198
+ pytest --cov=road24_sdk # Coverage report
199
+ ruff check . # Linting
200
+ ruff format . # Formatting
201
+ ```
202
+
203
+ ## Dependencies
204
+
205
+ **Required:**
206
+ - `prometheus-client` - Prometheus metrics
207
+
208
+ **Optional (extras):**
209
+ - `httpx` - HTTPX client integration
210
+ - `redis` - Redis client integration
211
+ - `sqlalchemy` - SQLAlchemy database integration
212
+
213
+ ## Anti-Patterns
214
+
215
+ - Don't break backwards compatibility without notice
216
+ - Don't add framework-specific logic (keep generic)
217
+ - Don't use `print()` anywhere
218
+ - Don't skip type hints
219
+ - Don't use synchronous I/O in async hooks
220
+ - Don't import optional deps at module level (use TYPE_CHECKING)
221
+ - Don't use Pydantic for schemas — use dataclasses with `slots=True`
222
+ - Don't use global variables — use `ContextVar` for request-scoped state
223
+
224
+ ## Testing
225
+
226
+ - All tests must be async (`@pytest.mark.asyncio`, auto mode configured)
227
+ - Mock all external dependencies (AsyncMock for async, Mock for sync)
228
+ - Use fixtures for test data in `tests/conftest.py`
229
+ - Use `@pytest.mark.parametrize` with dataclasses for multiple scenarios
230
+ - Follow AAA pattern (Arrange-Act-Assert)
231
+ - Target >90% coverage
232
+ - Test file structure mirrors source structure
233
+
234
+ ## Log Output Format
235
+
236
+ ```json
237
+ {
238
+ "timestamp": "2025-01-15T10:30:00.123Z",
239
+ "trace_id": "abc123...",
240
+ "log_level": "INFO",
241
+ "type": "db_query",
242
+ "service_name": "my-service",
243
+ "attributes": {
244
+ "operation": "select",
245
+ "table": "users",
246
+ "duration_seconds": 0.023,
247
+ "statement": "SELECT * FROM users WHERE id = 1"
248
+ }
249
+ }
250
+ ```
251
+
252
+ ## Prometheus Metrics
253
+
254
+ - `http_request_duration_seconds` / `http_requests_total` — Labels: `method`, `url`, `status_code`, `direction`
255
+ - `db_query_duration_seconds` / `db_queries_total` — Labels: `operation`, `table`
256
+ - `redis_command_duration_seconds` / `redis_commands_total` — Labels: `operation`, `key`