agent-first-data 0.2.3__tar.gz → 0.3.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.
- {agent_first_data-0.2.3/agent_first_data.egg-info → agent_first_data-0.3.0}/PKG-INFO +71 -33
- agent_first_data-0.2.3/PKG-INFO → agent_first_data-0.3.0/README.md +69 -40
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/agent_first_data/__init__.py +6 -8
- agent_first_data-0.2.3/agent_first_data/afd_logging.py → agent_first_data-0.3.0/agent_first_data/afdata_logging.py +15 -15
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/agent_first_data/format.py +2 -7
- agent_first_data-0.2.3/README.md → agent_first_data-0.3.0/agent_first_data.egg-info/PKG-INFO +78 -31
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/agent_first_data.egg-info/SOURCES.txt +2 -2
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/pyproject.toml +2 -2
- agent_first_data-0.2.3/tests/test_afd_logging.py → agent_first_data-0.3.0/tests/test_afdata_logging.py +11 -10
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/tests/test_format.py +1 -4
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/agent_first_data.egg-info/dependency_links.txt +0 -0
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/agent_first_data.egg-info/top_level.txt +0 -0
- {agent_first_data-0.2.3 → agent_first_data-0.3.0}/setup.cfg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-first-data
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Agent-First Data (
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates for AI agents
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/cmnspore/agent-first-data
|
|
7
7
|
Requires-Python: >=3.9
|
|
@@ -9,7 +9,7 @@ Description-Content-Type: text/markdown
|
|
|
9
9
|
|
|
10
10
|
# agent-first-data
|
|
11
11
|
|
|
12
|
-
**Agent-First Data (
|
|
12
|
+
**Agent-First Data (AFDATA)** — Suffix-driven output formatting and protocol templates for AI agents.
|
|
13
13
|
|
|
14
14
|
The field name is the schema. Agents read `latency_ms` and know milliseconds, `api_key_secret` and know to redact, no external schema needed.
|
|
15
15
|
|
|
@@ -27,24 +27,39 @@ A backup tool invoked from the CLI — flags, env vars, and config all use the s
|
|
|
27
27
|
API_KEY_SECRET=sk-1234 cloudback --timeout-s 30 --max-file-size-bytes 10737418240 /data/backup.tar.gz
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
For CLI diagnostics, enable log categories explicitly:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
--log startup,request,progress,retry,redirect
|
|
34
|
+
--verbose # shorthand for all categories
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Without these flags, startup diagnostics should stay off by default.
|
|
38
|
+
|
|
39
|
+
The tool reads env vars, flags, and config — all with AFDATA suffixes — and can emit a startup diagnostic event:
|
|
31
40
|
|
|
32
41
|
```python
|
|
33
42
|
from agent_first_data import *
|
|
34
43
|
import os
|
|
35
44
|
|
|
36
|
-
startup =
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
45
|
+
startup = build_json(
|
|
46
|
+
"log",
|
|
47
|
+
{
|
|
48
|
+
"event": "startup",
|
|
49
|
+
"config": {"timeout_s": 30, "max_file_size_bytes": 10737418240},
|
|
50
|
+
"args": {"input_path": "/data/backup.tar.gz"},
|
|
51
|
+
"env": {"API_KEY_SECRET": os.environ.get("API_KEY_SECRET")},
|
|
52
|
+
},
|
|
53
|
+
trace=None,
|
|
40
54
|
)
|
|
41
55
|
```
|
|
42
56
|
|
|
43
57
|
Three output formats, same data:
|
|
44
58
|
|
|
45
59
|
```
|
|
46
|
-
JSON: {"code":"startup","args":{"input_path":"/data/backup.tar.gz"},"config":{"max_file_size_bytes":10737418240,"timeout_s":30},"env":{"API_KEY_SECRET":"***"}}
|
|
47
|
-
YAML: code: "
|
|
60
|
+
JSON: {"code":"log","event":"startup","args":{"input_path":"/data/backup.tar.gz"},"config":{"max_file_size_bytes":10737418240,"timeout_s":30},"env":{"API_KEY_SECRET":"***"}}
|
|
61
|
+
YAML: code: "log"
|
|
62
|
+
event: "startup"
|
|
48
63
|
args:
|
|
49
64
|
input_path: "/data/backup.tar.gz"
|
|
50
65
|
config:
|
|
@@ -52,23 +67,20 @@ YAML: code: "startup"
|
|
|
52
67
|
timeout: "30s"
|
|
53
68
|
env:
|
|
54
69
|
API_KEY: "***"
|
|
55
|
-
Plain: args.input_path=/data/backup.tar.gz code=startup config.max_file_size=10.0GB config.timeout=30s env.API_KEY=***
|
|
70
|
+
Plain: args.input_path=/data/backup.tar.gz code=log event=startup config.max_file_size=10.0GB config.timeout=30s env.API_KEY=***
|
|
56
71
|
```
|
|
57
72
|
|
|
58
73
|
`--timeout-s` → `timeout_s` → `timeout: 30s`. `API_KEY_SECRET` → `API_KEY: "***"`. The suffix is the schema.
|
|
59
74
|
|
|
60
75
|
## API Reference
|
|
61
76
|
|
|
62
|
-
Total: **
|
|
77
|
+
Total: **8 public APIs** + **AFDATA logging** (3 protocol builders + 3 output functions + 1 internal + 1 utility)
|
|
63
78
|
|
|
64
79
|
### Protocol Builders (returns dict)
|
|
65
80
|
|
|
66
|
-
Build
|
|
81
|
+
Build AFDATA protocol structures. Return dict objects for API responses.
|
|
67
82
|
|
|
68
83
|
```python
|
|
69
|
-
# Startup (configuration)
|
|
70
|
-
build_json_startup(config: Any, args: Any, env: Any) -> dict
|
|
71
|
-
|
|
72
84
|
# Success (result)
|
|
73
85
|
build_json_ok(result: Any, trace: Any = None) -> dict
|
|
74
86
|
|
|
@@ -86,10 +98,15 @@ build_json(code: str, fields: Any, trace: Any = None) -> dict
|
|
|
86
98
|
from agent_first_data import *
|
|
87
99
|
|
|
88
100
|
# Startup
|
|
89
|
-
startup =
|
|
90
|
-
|
|
91
|
-
{
|
|
92
|
-
|
|
101
|
+
startup = build_json(
|
|
102
|
+
"log",
|
|
103
|
+
{
|
|
104
|
+
"event": "startup",
|
|
105
|
+
"config": {"api_key_secret": "sk-123", "timeout_s": 30},
|
|
106
|
+
"args": {"config_path": "config.yml"},
|
|
107
|
+
"env": {"RUST_LOG": "info"},
|
|
108
|
+
},
|
|
109
|
+
trace=None,
|
|
93
110
|
)
|
|
94
111
|
|
|
95
112
|
# Success (always include trace)
|
|
@@ -196,14 +213,20 @@ async def get_user(user_id: int):
|
|
|
196
213
|
from agent_first_data import *
|
|
197
214
|
|
|
198
215
|
# 1. Startup
|
|
199
|
-
startup =
|
|
200
|
-
|
|
201
|
-
{
|
|
202
|
-
|
|
216
|
+
startup = build_json(
|
|
217
|
+
"log",
|
|
218
|
+
{
|
|
219
|
+
"event": "startup",
|
|
220
|
+
"config": {"api_key_secret": "sk-sensitive-key", "timeout_s": 30},
|
|
221
|
+
"args": {"input_path": "data.json"},
|
|
222
|
+
"env": {"RUST_LOG": "info"},
|
|
223
|
+
},
|
|
224
|
+
trace=None,
|
|
203
225
|
)
|
|
204
226
|
print(output_yaml(startup))
|
|
205
227
|
# ---
|
|
206
|
-
# code: "
|
|
228
|
+
# code: "log"
|
|
229
|
+
# event: "startup"
|
|
207
230
|
# args:
|
|
208
231
|
# input_path: "data.json"
|
|
209
232
|
# config:
|
|
@@ -294,23 +317,23 @@ print(output_plain(data))
|
|
|
294
317
|
# api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
|
|
295
318
|
```
|
|
296
319
|
|
|
297
|
-
##
|
|
320
|
+
## AFDATA Logging
|
|
298
321
|
|
|
299
|
-
|
|
322
|
+
AFDATA-compliant structured logging via Python's `logging` module. Every log line is formatted using the library's own `output_json`/`output_plain`/`output_yaml` functions. Span fields are carried via `contextvars` (async-safe), automatically flattened into each log line.
|
|
300
323
|
|
|
301
324
|
### API
|
|
302
325
|
|
|
303
326
|
```python
|
|
304
327
|
from agent_first_data import init_logging_json, init_logging_plain, init_logging_yaml
|
|
305
|
-
from agent_first_data.
|
|
328
|
+
from agent_first_data.afdata_logging import AfdataHandler, get_logger, span
|
|
306
329
|
|
|
307
|
-
# Convenience initializers — set up the root logger with
|
|
330
|
+
# Convenience initializers — set up the root logger with AFDATA output to stdout
|
|
308
331
|
init_logging_json(level="INFO") # Single-line JSONL (secrets redacted, original keys)
|
|
309
332
|
init_logging_plain(level="INFO") # Single-line logfmt (keys stripped, values formatted)
|
|
310
333
|
init_logging_yaml(level="INFO") # Multi-line YAML (keys stripped, values formatted)
|
|
311
334
|
|
|
312
335
|
# Low-level — create a handler for custom logger stacks
|
|
313
|
-
|
|
336
|
+
AfdataHandler(format="json") # format: "json" | "plain" | "yaml"
|
|
314
337
|
|
|
315
338
|
# Logger with default fields (returns logging.LoggerAdapter)
|
|
316
339
|
get_logger(name, **fields)
|
|
@@ -391,8 +414,8 @@ The `code` field defaults to the log level. Override with an explicit field:
|
|
|
391
414
|
from agent_first_data import get_logger
|
|
392
415
|
|
|
393
416
|
logger = get_logger("myapp")
|
|
394
|
-
logger.info("Server ready", extra={"code": "startup"})
|
|
395
|
-
# {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"startup"}
|
|
417
|
+
logger.info("Server ready", extra={"code": "log", "event": "startup"})
|
|
418
|
+
# {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"log","event":"startup"}
|
|
396
419
|
```
|
|
397
420
|
|
|
398
421
|
### Output Fields
|
|
@@ -410,7 +433,7 @@ Every log line contains:
|
|
|
410
433
|
|
|
411
434
|
### Log Output Formats
|
|
412
435
|
|
|
413
|
-
All three formats use the library's own output functions, so
|
|
436
|
+
All three formats use the library's own output functions, so AFDATA suffix processing applies to log fields too:
|
|
414
437
|
|
|
415
438
|
| Format | Function | Keys | Values | Use case |
|
|
416
439
|
|:-------|:---------|:-----|:-------|:---------|
|
|
@@ -440,6 +463,21 @@ All formats automatically redact `_secret` fields.
|
|
|
440
463
|
- **Currency**: `_msats`, `_sats`, `_btc`, `_usd_cents`, `_eur_cents`, `_jpy`, `_{code}_cents`
|
|
441
464
|
- **Other**: `_percent`, `_secret` (auto-redacted in all formats)
|
|
442
465
|
|
|
466
|
+
## Repository
|
|
467
|
+
|
|
468
|
+
This package is part of the [agent-first-data](https://github.com/cmnspore/agent-first-data) repository, which also contains:
|
|
469
|
+
|
|
470
|
+
- **`spec/`** — Full AFDATA specification with suffix definitions, protocol format rules, and cross-language test fixtures
|
|
471
|
+
- **`skills/`** — AI coding agent skill for working with AFDATA conventions
|
|
472
|
+
|
|
473
|
+
To run tests, clone the full repository (tests use shared cross-language fixtures from `spec/fixtures/`):
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
git clone https://github.com/cmnspore/agent-first-data
|
|
477
|
+
cd agent-first-data/python
|
|
478
|
+
python -m pytest
|
|
479
|
+
```
|
|
480
|
+
|
|
443
481
|
## License
|
|
444
482
|
|
|
445
483
|
MIT
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: agent-first-data
|
|
3
|
-
Version: 0.2.3
|
|
4
|
-
Summary: Agent-First Data (AFD) — suffix-driven output formatting and protocol templates for AI agents
|
|
5
|
-
License-Expression: MIT
|
|
6
|
-
Project-URL: Repository, https://github.com/cmnspore/agent-first-data
|
|
7
|
-
Requires-Python: >=3.9
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
|
|
10
1
|
# agent-first-data
|
|
11
2
|
|
|
12
|
-
**Agent-First Data (
|
|
3
|
+
**Agent-First Data (AFDATA)** — Suffix-driven output formatting and protocol templates for AI agents.
|
|
13
4
|
|
|
14
5
|
The field name is the schema. Agents read `latency_ms` and know milliseconds, `api_key_secret` and know to redact, no external schema needed.
|
|
15
6
|
|
|
@@ -27,24 +18,39 @@ A backup tool invoked from the CLI — flags, env vars, and config all use the s
|
|
|
27
18
|
API_KEY_SECRET=sk-1234 cloudback --timeout-s 30 --max-file-size-bytes 10737418240 /data/backup.tar.gz
|
|
28
19
|
```
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
For CLI diagnostics, enable log categories explicitly:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
--log startup,request,progress,retry,redirect
|
|
25
|
+
--verbose # shorthand for all categories
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Without these flags, startup diagnostics should stay off by default.
|
|
29
|
+
|
|
30
|
+
The tool reads env vars, flags, and config — all with AFDATA suffixes — and can emit a startup diagnostic event:
|
|
31
31
|
|
|
32
32
|
```python
|
|
33
33
|
from agent_first_data import *
|
|
34
34
|
import os
|
|
35
35
|
|
|
36
|
-
startup =
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
36
|
+
startup = build_json(
|
|
37
|
+
"log",
|
|
38
|
+
{
|
|
39
|
+
"event": "startup",
|
|
40
|
+
"config": {"timeout_s": 30, "max_file_size_bytes": 10737418240},
|
|
41
|
+
"args": {"input_path": "/data/backup.tar.gz"},
|
|
42
|
+
"env": {"API_KEY_SECRET": os.environ.get("API_KEY_SECRET")},
|
|
43
|
+
},
|
|
44
|
+
trace=None,
|
|
40
45
|
)
|
|
41
46
|
```
|
|
42
47
|
|
|
43
48
|
Three output formats, same data:
|
|
44
49
|
|
|
45
50
|
```
|
|
46
|
-
JSON: {"code":"startup","args":{"input_path":"/data/backup.tar.gz"},"config":{"max_file_size_bytes":10737418240,"timeout_s":30},"env":{"API_KEY_SECRET":"***"}}
|
|
47
|
-
YAML: code: "
|
|
51
|
+
JSON: {"code":"log","event":"startup","args":{"input_path":"/data/backup.tar.gz"},"config":{"max_file_size_bytes":10737418240,"timeout_s":30},"env":{"API_KEY_SECRET":"***"}}
|
|
52
|
+
YAML: code: "log"
|
|
53
|
+
event: "startup"
|
|
48
54
|
args:
|
|
49
55
|
input_path: "/data/backup.tar.gz"
|
|
50
56
|
config:
|
|
@@ -52,23 +58,20 @@ YAML: code: "startup"
|
|
|
52
58
|
timeout: "30s"
|
|
53
59
|
env:
|
|
54
60
|
API_KEY: "***"
|
|
55
|
-
Plain: args.input_path=/data/backup.tar.gz code=startup config.max_file_size=10.0GB config.timeout=30s env.API_KEY=***
|
|
61
|
+
Plain: args.input_path=/data/backup.tar.gz code=log event=startup config.max_file_size=10.0GB config.timeout=30s env.API_KEY=***
|
|
56
62
|
```
|
|
57
63
|
|
|
58
64
|
`--timeout-s` → `timeout_s` → `timeout: 30s`. `API_KEY_SECRET` → `API_KEY: "***"`. The suffix is the schema.
|
|
59
65
|
|
|
60
66
|
## API Reference
|
|
61
67
|
|
|
62
|
-
Total: **
|
|
68
|
+
Total: **8 public APIs** + **AFDATA logging** (3 protocol builders + 3 output functions + 1 internal + 1 utility)
|
|
63
69
|
|
|
64
70
|
### Protocol Builders (returns dict)
|
|
65
71
|
|
|
66
|
-
Build
|
|
72
|
+
Build AFDATA protocol structures. Return dict objects for API responses.
|
|
67
73
|
|
|
68
74
|
```python
|
|
69
|
-
# Startup (configuration)
|
|
70
|
-
build_json_startup(config: Any, args: Any, env: Any) -> dict
|
|
71
|
-
|
|
72
75
|
# Success (result)
|
|
73
76
|
build_json_ok(result: Any, trace: Any = None) -> dict
|
|
74
77
|
|
|
@@ -86,10 +89,15 @@ build_json(code: str, fields: Any, trace: Any = None) -> dict
|
|
|
86
89
|
from agent_first_data import *
|
|
87
90
|
|
|
88
91
|
# Startup
|
|
89
|
-
startup =
|
|
90
|
-
|
|
91
|
-
{
|
|
92
|
-
|
|
92
|
+
startup = build_json(
|
|
93
|
+
"log",
|
|
94
|
+
{
|
|
95
|
+
"event": "startup",
|
|
96
|
+
"config": {"api_key_secret": "sk-123", "timeout_s": 30},
|
|
97
|
+
"args": {"config_path": "config.yml"},
|
|
98
|
+
"env": {"RUST_LOG": "info"},
|
|
99
|
+
},
|
|
100
|
+
trace=None,
|
|
93
101
|
)
|
|
94
102
|
|
|
95
103
|
# Success (always include trace)
|
|
@@ -196,14 +204,20 @@ async def get_user(user_id: int):
|
|
|
196
204
|
from agent_first_data import *
|
|
197
205
|
|
|
198
206
|
# 1. Startup
|
|
199
|
-
startup =
|
|
200
|
-
|
|
201
|
-
{
|
|
202
|
-
|
|
207
|
+
startup = build_json(
|
|
208
|
+
"log",
|
|
209
|
+
{
|
|
210
|
+
"event": "startup",
|
|
211
|
+
"config": {"api_key_secret": "sk-sensitive-key", "timeout_s": 30},
|
|
212
|
+
"args": {"input_path": "data.json"},
|
|
213
|
+
"env": {"RUST_LOG": "info"},
|
|
214
|
+
},
|
|
215
|
+
trace=None,
|
|
203
216
|
)
|
|
204
217
|
print(output_yaml(startup))
|
|
205
218
|
# ---
|
|
206
|
-
# code: "
|
|
219
|
+
# code: "log"
|
|
220
|
+
# event: "startup"
|
|
207
221
|
# args:
|
|
208
222
|
# input_path: "data.json"
|
|
209
223
|
# config:
|
|
@@ -294,23 +308,23 @@ print(output_plain(data))
|
|
|
294
308
|
# api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
|
|
295
309
|
```
|
|
296
310
|
|
|
297
|
-
##
|
|
311
|
+
## AFDATA Logging
|
|
298
312
|
|
|
299
|
-
|
|
313
|
+
AFDATA-compliant structured logging via Python's `logging` module. Every log line is formatted using the library's own `output_json`/`output_plain`/`output_yaml` functions. Span fields are carried via `contextvars` (async-safe), automatically flattened into each log line.
|
|
300
314
|
|
|
301
315
|
### API
|
|
302
316
|
|
|
303
317
|
```python
|
|
304
318
|
from agent_first_data import init_logging_json, init_logging_plain, init_logging_yaml
|
|
305
|
-
from agent_first_data.
|
|
319
|
+
from agent_first_data.afdata_logging import AfdataHandler, get_logger, span
|
|
306
320
|
|
|
307
|
-
# Convenience initializers — set up the root logger with
|
|
321
|
+
# Convenience initializers — set up the root logger with AFDATA output to stdout
|
|
308
322
|
init_logging_json(level="INFO") # Single-line JSONL (secrets redacted, original keys)
|
|
309
323
|
init_logging_plain(level="INFO") # Single-line logfmt (keys stripped, values formatted)
|
|
310
324
|
init_logging_yaml(level="INFO") # Multi-line YAML (keys stripped, values formatted)
|
|
311
325
|
|
|
312
326
|
# Low-level — create a handler for custom logger stacks
|
|
313
|
-
|
|
327
|
+
AfdataHandler(format="json") # format: "json" | "plain" | "yaml"
|
|
314
328
|
|
|
315
329
|
# Logger with default fields (returns logging.LoggerAdapter)
|
|
316
330
|
get_logger(name, **fields)
|
|
@@ -391,8 +405,8 @@ The `code` field defaults to the log level. Override with an explicit field:
|
|
|
391
405
|
from agent_first_data import get_logger
|
|
392
406
|
|
|
393
407
|
logger = get_logger("myapp")
|
|
394
|
-
logger.info("Server ready", extra={"code": "startup"})
|
|
395
|
-
# {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"startup"}
|
|
408
|
+
logger.info("Server ready", extra={"code": "log", "event": "startup"})
|
|
409
|
+
# {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"log","event":"startup"}
|
|
396
410
|
```
|
|
397
411
|
|
|
398
412
|
### Output Fields
|
|
@@ -410,7 +424,7 @@ Every log line contains:
|
|
|
410
424
|
|
|
411
425
|
### Log Output Formats
|
|
412
426
|
|
|
413
|
-
All three formats use the library's own output functions, so
|
|
427
|
+
All three formats use the library's own output functions, so AFDATA suffix processing applies to log fields too:
|
|
414
428
|
|
|
415
429
|
| Format | Function | Keys | Values | Use case |
|
|
416
430
|
|:-------|:---------|:-----|:-------|:---------|
|
|
@@ -440,6 +454,21 @@ All formats automatically redact `_secret` fields.
|
|
|
440
454
|
- **Currency**: `_msats`, `_sats`, `_btc`, `_usd_cents`, `_eur_cents`, `_jpy`, `_{code}_cents`
|
|
441
455
|
- **Other**: `_percent`, `_secret` (auto-redacted in all formats)
|
|
442
456
|
|
|
457
|
+
## Repository
|
|
458
|
+
|
|
459
|
+
This package is part of the [agent-first-data](https://github.com/cmnspore/agent-first-data) repository, which also contains:
|
|
460
|
+
|
|
461
|
+
- **`spec/`** — Full AFDATA specification with suffix definitions, protocol format rules, and cross-language test fixtures
|
|
462
|
+
- **`skills/`** — AI coding agent skill for working with AFDATA conventions
|
|
463
|
+
|
|
464
|
+
To run tests, clone the full repository (tests use shared cross-language fixtures from `spec/fixtures/`):
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
git clone https://github.com/cmnspore/agent-first-data
|
|
468
|
+
cd agent-first-data/python
|
|
469
|
+
python -m pytest
|
|
470
|
+
```
|
|
471
|
+
|
|
443
472
|
## License
|
|
444
473
|
|
|
445
474
|
MIT
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
"""Agent-First Data (
|
|
1
|
+
"""Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates."""
|
|
2
2
|
|
|
3
3
|
from agent_first_data.format import (
|
|
4
|
-
build_json_startup,
|
|
5
4
|
build_json_ok,
|
|
6
5
|
build_json_error,
|
|
7
6
|
build_json,
|
|
@@ -12,9 +11,9 @@ from agent_first_data.format import (
|
|
|
12
11
|
parse_size,
|
|
13
12
|
)
|
|
14
13
|
|
|
15
|
-
from agent_first_data.
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
from agent_first_data.afdata_logging import (
|
|
15
|
+
AfdataHandler,
|
|
16
|
+
AfdataJsonHandler,
|
|
18
17
|
init_json as init_logging_json,
|
|
19
18
|
init_plain as init_logging_plain,
|
|
20
19
|
init_yaml as init_logging_yaml,
|
|
@@ -23,7 +22,6 @@ from agent_first_data.afd_logging import (
|
|
|
23
22
|
)
|
|
24
23
|
|
|
25
24
|
__all__ = [
|
|
26
|
-
"build_json_startup",
|
|
27
25
|
"build_json_ok",
|
|
28
26
|
"build_json_error",
|
|
29
27
|
"build_json",
|
|
@@ -32,8 +30,8 @@ __all__ = [
|
|
|
32
30
|
"output_plain",
|
|
33
31
|
"internal_redact_secrets",
|
|
34
32
|
"parse_size",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
33
|
+
"AfdataHandler",
|
|
34
|
+
"AfdataJsonHandler",
|
|
37
35
|
"init_logging_json",
|
|
38
36
|
"init_logging_plain",
|
|
39
37
|
"init_logging_yaml",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""AFDATA-compliant structured logging.
|
|
2
2
|
|
|
3
3
|
Outputs log events using agent-first-data formatting functions:
|
|
4
4
|
- JSON: single-line JSONL via output_json (secrets redacted, original keys)
|
|
@@ -8,7 +8,7 @@ Outputs log events using agent-first-data formatting functions:
|
|
|
8
8
|
Span fields are carried via contextvars (async-safe).
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
|
-
from agent_first_data.
|
|
11
|
+
from agent_first_data.afdata_logging import init_json, init_plain, init_yaml, span
|
|
12
12
|
import logging
|
|
13
13
|
|
|
14
14
|
init_json("INFO") # or init_plain("INFO") or init_yaml("DEBUG")
|
|
@@ -25,7 +25,7 @@ from typing import Any
|
|
|
25
25
|
|
|
26
26
|
from agent_first_data.format import output_json, output_plain, output_yaml
|
|
27
27
|
|
|
28
|
-
_span_fields: ContextVar[dict[str, Any]] = ContextVar("
|
|
28
|
+
_span_fields: ContextVar[dict[str, Any]] = ContextVar("afdata_span", default={})
|
|
29
29
|
|
|
30
30
|
_LEVEL_TO_CODE = {
|
|
31
31
|
"CRITICAL": "error",
|
|
@@ -38,8 +38,8 @@ _LEVEL_TO_CODE = {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
class
|
|
42
|
-
"""Logging handler that outputs
|
|
41
|
+
class AfdataHandler(logging.Handler):
|
|
42
|
+
"""Logging handler that outputs AFDATA-compliant log lines to stdout.
|
|
43
43
|
|
|
44
44
|
Formats output using the library's own output_json/output_plain/output_yaml.
|
|
45
45
|
"""
|
|
@@ -64,7 +64,7 @@ class AfdHandler(logging.Handler):
|
|
|
64
64
|
|
|
65
65
|
# Event fields (passed via extra= in logging calls)
|
|
66
66
|
has_code = False
|
|
67
|
-
extra = getattr(record, "
|
|
67
|
+
extra = getattr(record, "_afdata_fields", None)
|
|
68
68
|
if extra:
|
|
69
69
|
for k, v in extra.items():
|
|
70
70
|
if k == "code":
|
|
@@ -88,11 +88,11 @@ class AfdHandler(logging.Handler):
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
# Keep old name as alias for backwards compat
|
|
91
|
-
|
|
91
|
+
AfdataJsonHandler = AfdataHandler
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
class
|
|
95
|
-
"""Logger adapter that passes extra fields to
|
|
94
|
+
class _AfdataLoggerAdapter(logging.LoggerAdapter):
|
|
95
|
+
"""Logger adapter that passes extra fields to AfdataHandler."""
|
|
96
96
|
|
|
97
97
|
def process(self, msg: str, kwargs: Any) -> tuple[str, Any]:
|
|
98
98
|
extra = kwargs.get("extra", {})
|
|
@@ -100,29 +100,29 @@ class _AfdLoggerAdapter(logging.LoggerAdapter):
|
|
|
100
100
|
merged = {**self.extra, **extra}
|
|
101
101
|
else:
|
|
102
102
|
merged = extra
|
|
103
|
-
kwargs["extra"] = {"
|
|
103
|
+
kwargs["extra"] = {"_afdata_fields": merged}
|
|
104
104
|
return msg, kwargs
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def _init_with_format(format: str, level: str = "INFO") -> None:
|
|
108
|
-
handler =
|
|
108
|
+
handler = AfdataHandler(format=format)
|
|
109
109
|
root = logging.getLogger()
|
|
110
110
|
root.handlers = [handler]
|
|
111
111
|
root.setLevel(getattr(logging, level.upper(), logging.INFO))
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
def init_json(level: str = "INFO") -> None:
|
|
115
|
-
"""Initialize the root logger with
|
|
115
|
+
"""Initialize the root logger with AFDATA JSON output to stdout."""
|
|
116
116
|
_init_with_format("json", level)
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
def init_plain(level: str = "INFO") -> None:
|
|
120
|
-
"""Initialize the root logger with
|
|
120
|
+
"""Initialize the root logger with AFDATA plain/logfmt output to stdout."""
|
|
121
121
|
_init_with_format("plain", level)
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
def init_yaml(level: str = "INFO") -> None:
|
|
125
|
-
"""Initialize the root logger with
|
|
125
|
+
"""Initialize the root logger with AFDATA YAML output to stdout."""
|
|
126
126
|
_init_with_format("yaml", level)
|
|
127
127
|
|
|
128
128
|
|
|
@@ -133,7 +133,7 @@ def get_logger(name: str, **fields: Any) -> logging.LoggerAdapter:
|
|
|
133
133
|
Use for per-module or per-component fields.
|
|
134
134
|
"""
|
|
135
135
|
base = logging.getLogger(name)
|
|
136
|
-
return
|
|
136
|
+
return _AfdataLoggerAdapter(base, fields)
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
class span:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""AFDATA output formatting and protocol templates.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
8 public APIs: 3 protocol builders + 3 output formatters + 1 redaction + 1 utility.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
@@ -16,11 +16,6 @@ from typing import Any
|
|
|
16
16
|
# ═══════════════════════════════════════════
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def build_json_startup(config: Any, args: Any, env: Any) -> dict:
|
|
20
|
-
"""Build {code: "startup", config, args, env}."""
|
|
21
|
-
return {"code": "startup", "config": config, "args": args, "env": env}
|
|
22
|
-
|
|
23
|
-
|
|
24
19
|
def build_json_ok(result: Any, trace: Any = None) -> dict:
|
|
25
20
|
"""Build {code: "ok", result, trace?}."""
|
|
26
21
|
m: dict = {"code": "ok", "result": result}
|
agent_first_data-0.2.3/README.md → agent_first_data-0.3.0/agent_first_data.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-first-data
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates for AI agents
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Repository, https://github.com/cmnspore/agent-first-data
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
1
10
|
# agent-first-data
|
|
2
11
|
|
|
3
|
-
**Agent-First Data (
|
|
12
|
+
**Agent-First Data (AFDATA)** — Suffix-driven output formatting and protocol templates for AI agents.
|
|
4
13
|
|
|
5
14
|
The field name is the schema. Agents read `latency_ms` and know milliseconds, `api_key_secret` and know to redact, no external schema needed.
|
|
6
15
|
|
|
@@ -18,24 +27,39 @@ A backup tool invoked from the CLI — flags, env vars, and config all use the s
|
|
|
18
27
|
API_KEY_SECRET=sk-1234 cloudback --timeout-s 30 --max-file-size-bytes 10737418240 /data/backup.tar.gz
|
|
19
28
|
```
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
For CLI diagnostics, enable log categories explicitly:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
--log startup,request,progress,retry,redirect
|
|
34
|
+
--verbose # shorthand for all categories
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Without these flags, startup diagnostics should stay off by default.
|
|
38
|
+
|
|
39
|
+
The tool reads env vars, flags, and config — all with AFDATA suffixes — and can emit a startup diagnostic event:
|
|
22
40
|
|
|
23
41
|
```python
|
|
24
42
|
from agent_first_data import *
|
|
25
43
|
import os
|
|
26
44
|
|
|
27
|
-
startup =
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
|
|
45
|
+
startup = build_json(
|
|
46
|
+
"log",
|
|
47
|
+
{
|
|
48
|
+
"event": "startup",
|
|
49
|
+
"config": {"timeout_s": 30, "max_file_size_bytes": 10737418240},
|
|
50
|
+
"args": {"input_path": "/data/backup.tar.gz"},
|
|
51
|
+
"env": {"API_KEY_SECRET": os.environ.get("API_KEY_SECRET")},
|
|
52
|
+
},
|
|
53
|
+
trace=None,
|
|
31
54
|
)
|
|
32
55
|
```
|
|
33
56
|
|
|
34
57
|
Three output formats, same data:
|
|
35
58
|
|
|
36
59
|
```
|
|
37
|
-
JSON: {"code":"startup","args":{"input_path":"/data/backup.tar.gz"},"config":{"max_file_size_bytes":10737418240,"timeout_s":30},"env":{"API_KEY_SECRET":"***"}}
|
|
38
|
-
YAML: code: "
|
|
60
|
+
JSON: {"code":"log","event":"startup","args":{"input_path":"/data/backup.tar.gz"},"config":{"max_file_size_bytes":10737418240,"timeout_s":30},"env":{"API_KEY_SECRET":"***"}}
|
|
61
|
+
YAML: code: "log"
|
|
62
|
+
event: "startup"
|
|
39
63
|
args:
|
|
40
64
|
input_path: "/data/backup.tar.gz"
|
|
41
65
|
config:
|
|
@@ -43,23 +67,20 @@ YAML: code: "startup"
|
|
|
43
67
|
timeout: "30s"
|
|
44
68
|
env:
|
|
45
69
|
API_KEY: "***"
|
|
46
|
-
Plain: args.input_path=/data/backup.tar.gz code=startup config.max_file_size=10.0GB config.timeout=30s env.API_KEY=***
|
|
70
|
+
Plain: args.input_path=/data/backup.tar.gz code=log event=startup config.max_file_size=10.0GB config.timeout=30s env.API_KEY=***
|
|
47
71
|
```
|
|
48
72
|
|
|
49
73
|
`--timeout-s` → `timeout_s` → `timeout: 30s`. `API_KEY_SECRET` → `API_KEY: "***"`. The suffix is the schema.
|
|
50
74
|
|
|
51
75
|
## API Reference
|
|
52
76
|
|
|
53
|
-
Total: **
|
|
77
|
+
Total: **8 public APIs** + **AFDATA logging** (3 protocol builders + 3 output functions + 1 internal + 1 utility)
|
|
54
78
|
|
|
55
79
|
### Protocol Builders (returns dict)
|
|
56
80
|
|
|
57
|
-
Build
|
|
81
|
+
Build AFDATA protocol structures. Return dict objects for API responses.
|
|
58
82
|
|
|
59
83
|
```python
|
|
60
|
-
# Startup (configuration)
|
|
61
|
-
build_json_startup(config: Any, args: Any, env: Any) -> dict
|
|
62
|
-
|
|
63
84
|
# Success (result)
|
|
64
85
|
build_json_ok(result: Any, trace: Any = None) -> dict
|
|
65
86
|
|
|
@@ -77,10 +98,15 @@ build_json(code: str, fields: Any, trace: Any = None) -> dict
|
|
|
77
98
|
from agent_first_data import *
|
|
78
99
|
|
|
79
100
|
# Startup
|
|
80
|
-
startup =
|
|
81
|
-
|
|
82
|
-
{
|
|
83
|
-
|
|
101
|
+
startup = build_json(
|
|
102
|
+
"log",
|
|
103
|
+
{
|
|
104
|
+
"event": "startup",
|
|
105
|
+
"config": {"api_key_secret": "sk-123", "timeout_s": 30},
|
|
106
|
+
"args": {"config_path": "config.yml"},
|
|
107
|
+
"env": {"RUST_LOG": "info"},
|
|
108
|
+
},
|
|
109
|
+
trace=None,
|
|
84
110
|
)
|
|
85
111
|
|
|
86
112
|
# Success (always include trace)
|
|
@@ -187,14 +213,20 @@ async def get_user(user_id: int):
|
|
|
187
213
|
from agent_first_data import *
|
|
188
214
|
|
|
189
215
|
# 1. Startup
|
|
190
|
-
startup =
|
|
191
|
-
|
|
192
|
-
{
|
|
193
|
-
|
|
216
|
+
startup = build_json(
|
|
217
|
+
"log",
|
|
218
|
+
{
|
|
219
|
+
"event": "startup",
|
|
220
|
+
"config": {"api_key_secret": "sk-sensitive-key", "timeout_s": 30},
|
|
221
|
+
"args": {"input_path": "data.json"},
|
|
222
|
+
"env": {"RUST_LOG": "info"},
|
|
223
|
+
},
|
|
224
|
+
trace=None,
|
|
194
225
|
)
|
|
195
226
|
print(output_yaml(startup))
|
|
196
227
|
# ---
|
|
197
|
-
# code: "
|
|
228
|
+
# code: "log"
|
|
229
|
+
# event: "startup"
|
|
198
230
|
# args:
|
|
199
231
|
# input_path: "data.json"
|
|
200
232
|
# config:
|
|
@@ -285,23 +317,23 @@ print(output_plain(data))
|
|
|
285
317
|
# api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
|
|
286
318
|
```
|
|
287
319
|
|
|
288
|
-
##
|
|
320
|
+
## AFDATA Logging
|
|
289
321
|
|
|
290
|
-
|
|
322
|
+
AFDATA-compliant structured logging via Python's `logging` module. Every log line is formatted using the library's own `output_json`/`output_plain`/`output_yaml` functions. Span fields are carried via `contextvars` (async-safe), automatically flattened into each log line.
|
|
291
323
|
|
|
292
324
|
### API
|
|
293
325
|
|
|
294
326
|
```python
|
|
295
327
|
from agent_first_data import init_logging_json, init_logging_plain, init_logging_yaml
|
|
296
|
-
from agent_first_data.
|
|
328
|
+
from agent_first_data.afdata_logging import AfdataHandler, get_logger, span
|
|
297
329
|
|
|
298
|
-
# Convenience initializers — set up the root logger with
|
|
330
|
+
# Convenience initializers — set up the root logger with AFDATA output to stdout
|
|
299
331
|
init_logging_json(level="INFO") # Single-line JSONL (secrets redacted, original keys)
|
|
300
332
|
init_logging_plain(level="INFO") # Single-line logfmt (keys stripped, values formatted)
|
|
301
333
|
init_logging_yaml(level="INFO") # Multi-line YAML (keys stripped, values formatted)
|
|
302
334
|
|
|
303
335
|
# Low-level — create a handler for custom logger stacks
|
|
304
|
-
|
|
336
|
+
AfdataHandler(format="json") # format: "json" | "plain" | "yaml"
|
|
305
337
|
|
|
306
338
|
# Logger with default fields (returns logging.LoggerAdapter)
|
|
307
339
|
get_logger(name, **fields)
|
|
@@ -382,8 +414,8 @@ The `code` field defaults to the log level. Override with an explicit field:
|
|
|
382
414
|
from agent_first_data import get_logger
|
|
383
415
|
|
|
384
416
|
logger = get_logger("myapp")
|
|
385
|
-
logger.info("Server ready", extra={"code": "startup"})
|
|
386
|
-
# {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"startup"}
|
|
417
|
+
logger.info("Server ready", extra={"code": "log", "event": "startup"})
|
|
418
|
+
# {"timestamp_epoch_ms":...,"message":"Server ready","target":"myapp","code":"log","event":"startup"}
|
|
387
419
|
```
|
|
388
420
|
|
|
389
421
|
### Output Fields
|
|
@@ -401,7 +433,7 @@ Every log line contains:
|
|
|
401
433
|
|
|
402
434
|
### Log Output Formats
|
|
403
435
|
|
|
404
|
-
All three formats use the library's own output functions, so
|
|
436
|
+
All three formats use the library's own output functions, so AFDATA suffix processing applies to log fields too:
|
|
405
437
|
|
|
406
438
|
| Format | Function | Keys | Values | Use case |
|
|
407
439
|
|:-------|:---------|:-----|:-------|:---------|
|
|
@@ -431,6 +463,21 @@ All formats automatically redact `_secret` fields.
|
|
|
431
463
|
- **Currency**: `_msats`, `_sats`, `_btc`, `_usd_cents`, `_eur_cents`, `_jpy`, `_{code}_cents`
|
|
432
464
|
- **Other**: `_percent`, `_secret` (auto-redacted in all formats)
|
|
433
465
|
|
|
466
|
+
## Repository
|
|
467
|
+
|
|
468
|
+
This package is part of the [agent-first-data](https://github.com/cmnspore/agent-first-data) repository, which also contains:
|
|
469
|
+
|
|
470
|
+
- **`spec/`** — Full AFDATA specification with suffix definitions, protocol format rules, and cross-language test fixtures
|
|
471
|
+
- **`skills/`** — AI coding agent skill for working with AFDATA conventions
|
|
472
|
+
|
|
473
|
+
To run tests, clone the full repository (tests use shared cross-language fixtures from `spec/fixtures/`):
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
git clone https://github.com/cmnspore/agent-first-data
|
|
477
|
+
cd agent-first-data/python
|
|
478
|
+
python -m pytest
|
|
479
|
+
```
|
|
480
|
+
|
|
434
481
|
## License
|
|
435
482
|
|
|
436
483
|
MIT
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
README.md
|
|
2
2
|
pyproject.toml
|
|
3
3
|
agent_first_data/__init__.py
|
|
4
|
-
agent_first_data/
|
|
4
|
+
agent_first_data/afdata_logging.py
|
|
5
5
|
agent_first_data/format.py
|
|
6
6
|
agent_first_data.egg-info/PKG-INFO
|
|
7
7
|
agent_first_data.egg-info/SOURCES.txt
|
|
8
8
|
agent_first_data.egg-info/dependency_links.txt
|
|
9
9
|
agent_first_data.egg-info/top_level.txt
|
|
10
|
-
tests/
|
|
10
|
+
tests/test_afdata_logging.py
|
|
11
11
|
tests/test_format.py
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agent-first-data"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "Agent-First Data (
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates for AI agents"
|
|
5
5
|
license = "MIT"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
requires-python = ">=3.9"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Tests for
|
|
1
|
+
"""Tests for AFDATA logging module."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
from io import StringIO
|
|
7
7
|
from unittest.mock import patch
|
|
8
8
|
|
|
9
|
-
from agent_first_data.
|
|
9
|
+
from agent_first_data.afdata_logging import AfdataHandler, AfdataJsonHandler, init_json, init_plain, init_yaml, span, get_logger
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def capture_log(fn):
|
|
@@ -20,9 +20,9 @@ def capture_log(fn):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def make_logger(name="test"):
|
|
23
|
-
"""Create a fresh logger with
|
|
23
|
+
"""Create a fresh logger with AfdataJsonHandler."""
|
|
24
24
|
logger = logging.getLogger(name)
|
|
25
|
-
logger.handlers = [
|
|
25
|
+
logger.handlers = [AfdataJsonHandler()]
|
|
26
26
|
logger.setLevel(logging.DEBUG)
|
|
27
27
|
return logger
|
|
28
28
|
|
|
@@ -108,15 +108,16 @@ class TestCodeOverride:
|
|
|
108
108
|
logger = make_logger("test_code")
|
|
109
109
|
adapter = get_logger("test_code")
|
|
110
110
|
|
|
111
|
-
m = capture_log(lambda: adapter.info("ready", extra={"code": "startup"}))
|
|
112
|
-
assert m["code"] == "
|
|
111
|
+
m = capture_log(lambda: adapter.info("ready", extra={"code": "log", "event": "startup"}))
|
|
112
|
+
assert m["code"] == "log"
|
|
113
|
+
assert m["event"] == "startup"
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
class TestGetLogger:
|
|
116
117
|
def test_default_fields(self):
|
|
117
|
-
# Ensure root logger has
|
|
118
|
+
# Ensure root logger has AfdataJsonHandler
|
|
118
119
|
root = logging.getLogger()
|
|
119
|
-
root.handlers = [
|
|
120
|
+
root.handlers = [AfdataJsonHandler()]
|
|
120
121
|
root.setLevel(logging.DEBUG)
|
|
121
122
|
|
|
122
123
|
adapter = get_logger("test_adapter", component="myservice")
|
|
@@ -137,7 +138,7 @@ def capture_raw(fn):
|
|
|
137
138
|
class TestPlainFormat:
|
|
138
139
|
def test_plain_output(self):
|
|
139
140
|
logger = logging.getLogger("test_plain")
|
|
140
|
-
logger.handlers = [
|
|
141
|
+
logger.handlers = [AfdataHandler(format="plain")]
|
|
141
142
|
logger.setLevel(logging.DEBUG)
|
|
142
143
|
|
|
143
144
|
output = capture_raw(lambda: logger.info("hello"))
|
|
@@ -157,7 +158,7 @@ class TestPlainFormat:
|
|
|
157
158
|
class TestYamlFormat:
|
|
158
159
|
def test_yaml_output(self):
|
|
159
160
|
logger = logging.getLogger("test_yaml")
|
|
160
|
-
logger.handlers = [
|
|
161
|
+
logger.handlers = [AfdataHandler(format="yaml")]
|
|
161
162
|
logger.setLevel(logging.DEBUG)
|
|
162
163
|
|
|
163
164
|
output = capture_raw(lambda: logger.info("hello"))
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
"""Tests for
|
|
1
|
+
"""Tests for AFDATA output formatting — driven by shared spec/fixtures."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
6
|
from agent_first_data import (
|
|
7
|
-
build_json_startup,
|
|
8
7
|
build_json_ok,
|
|
9
8
|
build_json_error,
|
|
10
9
|
build_json,
|
|
@@ -52,8 +51,6 @@ def test_protocol_fixtures():
|
|
|
52
51
|
result = build_json_error(args["message"])
|
|
53
52
|
elif typ == "error_trace":
|
|
54
53
|
result = build_json_error(args["message"], args["trace"])
|
|
55
|
-
elif typ == "startup":
|
|
56
|
-
result = build_json_startup(args["config"], args["args"], args["env"])
|
|
57
54
|
elif typ == "status":
|
|
58
55
|
result = build_json(args["code"], args.get("fields"))
|
|
59
56
|
else:
|
{agent_first_data-0.2.3 → agent_first_data-0.3.0}/agent_first_data.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|