log-foundry 0.10.2.dev2__tar.gz → 0.10.2.dev4__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.
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/PKG-INFO +1 -1
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/pyproject.toml +1 -1
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/context.py +52 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/decorator.py +16 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/LICENSE +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/README.md +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/__init__.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/api.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/config.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/console.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/ids.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/model.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/py.typed +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sanitize.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/__init__.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/_batch.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/_chunk.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/_socket.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/_time.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/base.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/callback.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/clickhouse.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/datadog.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/elasticsearch.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/eventhubs.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/file.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/filtering.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/firehose.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/honeycomb.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/http.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/kafka.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/kinesis.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/logging_sink.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/logstash.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/loki.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/mongodb.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/multi.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/nats.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/newrelic.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/postgres.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/pubsub.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/rabbitmq.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/redis.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/sentry.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/sns.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/splunk.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/sqlite.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/sqs.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/stdout.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/syslog.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/transform.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/sinks/util.py +0 -0
- {log_foundry-0.10.2.dev2 → log_foundry-0.10.2.dev4}/src/log_foundry/worker.py +0 -0
|
@@ -29,7 +29,9 @@ __all__ = [
|
|
|
29
29
|
"current_trace_context",
|
|
30
30
|
"current_traceparent",
|
|
31
31
|
"get_baggage",
|
|
32
|
+
"pop_baggage_scope",
|
|
32
33
|
"pop_span",
|
|
34
|
+
"push_baggage_scope",
|
|
33
35
|
"push_span",
|
|
34
36
|
"set_baggage",
|
|
35
37
|
]
|
|
@@ -81,6 +83,56 @@ def set_baggage(**kv: object) -> None:
|
|
|
81
83
|
_baggage.set({**_baggage.get(), **kv})
|
|
82
84
|
|
|
83
85
|
|
|
86
|
+
# -- the root-span scope (SPEC-024) ------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def push_baggage_scope() -> contextvars.Token[dict[str, object]]:
|
|
90
|
+
"""Open a root span's baggage scope; hand the token back to :func:`pop_baggage_scope`.
|
|
91
|
+
|
|
92
|
+
Setting the variable to its own current value is what mints the token — there is no other
|
|
93
|
+
way to say "restore whatever was here", including the case where nothing was ever set. It
|
|
94
|
+
is safe because no baggage dict is ever mutated in place (see this module's docstring).
|
|
95
|
+
"""
|
|
96
|
+
return _baggage.set(_baggage.get())
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def pop_baggage_scope(token: contextvars.Token[dict[str, object]]) -> None:
|
|
100
|
+
"""Close a root span's scope: restore baggage, discard any adopted trace context.
|
|
101
|
+
|
|
102
|
+
The two are deliberately **asymmetric**. Baggage is *restored*, so a process-level default
|
|
103
|
+
set before any span outlives the traces that run under it while a request's own keys do not
|
|
104
|
+
(SPEC-024 FR-001). The adopted context is *cleared*, because it is a one-shot handoff to the
|
|
105
|
+
trace it was adopted for: restoring it would leave the next invocation still joining the
|
|
106
|
+
previous caller's trace, which is the defect this scope exists to close (FR-002). A caller
|
|
107
|
+
who opens no span at all clears both with :func:`reset_context`.
|
|
108
|
+
|
|
109
|
+
Total — never raises, because a decorated function must not fail on the way out (arch §4).
|
|
110
|
+
|
|
111
|
+
One caveat the ``contextvars`` model makes unavoidable: both writes land in the context the
|
|
112
|
+
root span's ``finally`` runs in. An adoption made *outside* a span that then runs in a child
|
|
113
|
+
context — any ``asyncio.Task``, including the one ``asyncio.run`` creates — is cleared in
|
|
114
|
+
the copy, not in the parent that holds it. :func:`continue_trace` is documented to be called on
|
|
115
|
+
the entry point's first line, which is inside the span and unaffected; a caller who adopts
|
|
116
|
+
before dispatching across a task boundary clears it with :func:`reset_context`.
|
|
117
|
+
"""
|
|
118
|
+
# Cleared first, and deliberately ahead of anything that could fail: a stale trace id puts
|
|
119
|
+
# *wrong* data in the log stream, while a missed baggage restore only leaves a stale field.
|
|
120
|
+
_adopted.set(None)
|
|
121
|
+
try:
|
|
122
|
+
_baggage.reset(token)
|
|
123
|
+
except Exception:
|
|
124
|
+
# `reset` rejects a token minted in another context (``ValueError``, reachable when a
|
|
125
|
+
# span body hands work to another thread) and one already used (``RuntimeError``).
|
|
126
|
+
# Setting the captured value directly is equivalent: this context never had the scope
|
|
127
|
+
# pushed onto it, so there is nothing else to unwind. Broad because the alternative is
|
|
128
|
+
# raising from a `finally` and replacing the caller's own exception (arch §4).
|
|
129
|
+
# `old_value` is ``Token.MISSING`` when the variable was unset at capture, and absent
|
|
130
|
+
# entirely if this was never a Token; neither can have come from `set_baggage`, so both
|
|
131
|
+
# land on empty rather than poisoning baggage with whatever was passed.
|
|
132
|
+
old = getattr(token, "old_value", None)
|
|
133
|
+
_baggage.set(old if isinstance(old, dict) else {})
|
|
134
|
+
|
|
135
|
+
|
|
84
136
|
# -- adopted inbound context (SPEC-014) --------------------------------------------------
|
|
85
137
|
|
|
86
138
|
|
|
@@ -114,6 +114,12 @@ def continue_trace(
|
|
|
114
114
|
Call it on the **first line** of the entry point: a child span that already finished has
|
|
115
115
|
been handed to the worker and can no longer be rewritten.
|
|
116
116
|
|
|
117
|
+
The adoption is **consumed by that one root span** and does not survive it (SPEC-024): the
|
|
118
|
+
next root span opened with no fresh call of its own starts a new trace, which is what stops
|
|
119
|
+
a warm container from logging every later invocation into the first caller's trace. So a
|
|
120
|
+
batch that fans out to several *sibling* root spans needs one call per item — or, better, a
|
|
121
|
+
single ``@trace`` entry point so the items are nested spans of one trace.
|
|
122
|
+
|
|
117
123
|
``baggage`` is a W3C ``baggage`` header merged into the current context. It succeeds or
|
|
118
124
|
fails independently of the trace context.
|
|
119
125
|
|
|
@@ -298,8 +304,11 @@ def trace(
|
|
|
298
304
|
|
|
299
305
|
@functools.wraps(fn)
|
|
300
306
|
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
307
|
+
# Before _open_span, which is what makes the new span current (SPEC-024).
|
|
308
|
+
is_root = context.current_span() is None
|
|
301
309
|
span = _open_span(name or fn.__qualname__, defaults)
|
|
302
310
|
token = context.push_span(span)
|
|
311
|
+
scope = context.push_baggage_scope() if is_root else None
|
|
303
312
|
try:
|
|
304
313
|
result = await fn(*args, **kwargs)
|
|
305
314
|
_close_span(span, "ok", None)
|
|
@@ -312,13 +321,18 @@ def trace(
|
|
|
312
321
|
raise
|
|
313
322
|
finally:
|
|
314
323
|
context.pop_span(token)
|
|
324
|
+
if scope is not None:
|
|
325
|
+
context.pop_baggage_scope(scope)
|
|
315
326
|
|
|
316
327
|
return cast("F", async_wrapper)
|
|
317
328
|
|
|
318
329
|
@functools.wraps(fn)
|
|
319
330
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
331
|
+
# Before _open_span, which is what makes the new span current (SPEC-024).
|
|
332
|
+
is_root = context.current_span() is None
|
|
320
333
|
span = _open_span(name or fn.__qualname__, defaults)
|
|
321
334
|
token = context.push_span(span)
|
|
335
|
+
scope = context.push_baggage_scope() if is_root else None
|
|
322
336
|
try:
|
|
323
337
|
result = fn(*args, **kwargs)
|
|
324
338
|
_close_span(span, "ok", None)
|
|
@@ -329,6 +343,8 @@ def trace(
|
|
|
329
343
|
raise
|
|
330
344
|
finally:
|
|
331
345
|
context.pop_span(token)
|
|
346
|
+
if scope is not None:
|
|
347
|
+
context.pop_baggage_scope(scope)
|
|
332
348
|
|
|
333
349
|
return cast("F", wrapper)
|
|
334
350
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|