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.
- road24_artifacthub-0.1.0/.claude/CLAUDE.md +151 -0
- road24_artifacthub-0.1.0/.claude/agents/engineer.md +256 -0
- road24_artifacthub-0.1.0/.claude/agents/tester.md +495 -0
- road24_artifacthub-0.1.0/.gitignore +18 -0
- road24_artifacthub-0.1.0/.hooks/check-commit-msg.sh +16 -0
- road24_artifacthub-0.1.0/.pre-commit-config.yaml +49 -0
- road24_artifacthub-0.1.0/Makefile +37 -0
- road24_artifacthub-0.1.0/PKG-INFO +122 -0
- road24_artifacthub-0.1.0/README.md +86 -0
- road24_artifacthub-0.1.0/commands/__init__.py +0 -0
- road24_artifacthub-0.1.0/commands/test_logs_db.py +44 -0
- road24_artifacthub-0.1.0/commands/test_logs_exceptions.py +59 -0
- road24_artifacthub-0.1.0/commands/test_logs_http_input.py +106 -0
- road24_artifacthub-0.1.0/commands/test_logs_http_output.py +35 -0
- road24_artifacthub-0.1.0/commands/test_logs_redis.py +34 -0
- road24_artifacthub-0.1.0/commands/test_metrics_http.py +54 -0
- road24_artifacthub-0.1.0/examples/__init__.py +0 -0
- road24_artifacthub-0.1.0/examples/core/__init__.py +0 -0
- road24_artifacthub-0.1.0/examples/core/database/__init__.py +0 -0
- road24_artifacthub-0.1.0/examples/core/database/config.py +39 -0
- road24_artifacthub-0.1.0/examples/core/database/mixins.py +37 -0
- road24_artifacthub-0.1.0/examples/core/http.py +53 -0
- road24_artifacthub-0.1.0/examples/core/redis.py +80 -0
- road24_artifacthub-0.1.0/examples/core/road24.py +26 -0
- road24_artifacthub-0.1.0/examples/core/settings.py +57 -0
- road24_artifacthub-0.1.0/examples/core/utils.py +8 -0
- road24_artifacthub-0.1.0/examples/src/__init__.py +0 -0
- road24_artifacthub-0.1.0/examples/src/main.py +33 -0
- road24_artifacthub-0.1.0/main.py +6 -0
- road24_artifacthub-0.1.0/pyproject.toml +56 -0
- road24_artifacthub-0.1.0/road24_sdk/__init__.py +65 -0
- road24_artifacthub-0.1.0/road24_sdk/_formatter.py +213 -0
- road24_artifacthub-0.1.0/road24_sdk/_sanitizer.py +61 -0
- road24_artifacthub-0.1.0/road24_sdk/_schemas.py +117 -0
- road24_artifacthub-0.1.0/road24_sdk/_types.py +54 -0
- road24_artifacthub-0.1.0/road24_sdk/integrations/__init__.py +13 -0
- road24_artifacthub-0.1.0/road24_sdk/integrations/_base.py +19 -0
- road24_artifacthub-0.1.0/road24_sdk/integrations/fastapi.py +258 -0
- road24_artifacthub-0.1.0/road24_sdk/integrations/httpx.py +120 -0
- road24_artifacthub-0.1.0/road24_sdk/integrations/redis.py +233 -0
- road24_artifacthub-0.1.0/road24_sdk/integrations/sqlalchemy.py +175 -0
- road24_artifacthub-0.1.0/road24_sdk/metrics/__init__.py +9 -0
- road24_artifacthub-0.1.0/road24_sdk/metrics/db.py +29 -0
- road24_artifacthub-0.1.0/road24_sdk/metrics/http.py +33 -0
- road24_artifacthub-0.1.0/road24_sdk/metrics/redis.py +29 -0
- road24_artifacthub-0.1.0/tests/__init__.py +0 -0
- road24_artifacthub-0.1.0/tests/conftest.py +170 -0
- road24_artifacthub-0.1.0/tests/test_data_classes.py +81 -0
- road24_artifacthub-0.1.0/tests/test_formatter.py +446 -0
- road24_artifacthub-0.1.0/tests/test_init.py +85 -0
- road24_artifacthub-0.1.0/tests/test_integrations/__init__.py +0 -0
- road24_artifacthub-0.1.0/tests/test_integrations/test_base.py +50 -0
- road24_artifacthub-0.1.0/tests/test_integrations/test_fastapi.py +803 -0
- road24_artifacthub-0.1.0/tests/test_integrations/test_httpx.py +512 -0
- road24_artifacthub-0.1.0/tests/test_integrations/test_redis.py +395 -0
- road24_artifacthub-0.1.0/tests/test_integrations/test_sqlalchemy.py +374 -0
- road24_artifacthub-0.1.0/tests/test_metrics/__init__.py +0 -0
- road24_artifacthub-0.1.0/tests/test_metrics/test_db.py +183 -0
- road24_artifacthub-0.1.0/tests/test_metrics/test_http.py +199 -0
- road24_artifacthub-0.1.0/tests/test_metrics/test_redis.py +201 -0
- road24_artifacthub-0.1.0/tests/test_sanitizer.py +325 -0
- road24_artifacthub-0.1.0/tests/test_schemas.py +385 -0
- road24_artifacthub-0.1.0/tests/test_types.py +411 -0
- 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`
|