log-foundry 0.3.1.dev1__tar.gz → 0.3.1.dev2__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 (51) hide show
  1. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/PKG-INFO +1 -1
  2. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/pyproject.toml +1 -1
  3. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/decorator.py +10 -2
  4. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/model.py +30 -1
  5. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/LICENSE +0 -0
  6. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/README.md +0 -0
  7. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/__init__.py +0 -0
  8. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/api.py +0 -0
  9. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/config.py +0 -0
  10. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/console.py +0 -0
  11. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/context.py +0 -0
  12. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/ids.py +0 -0
  13. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/py.typed +0 -0
  14. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/__init__.py +0 -0
  15. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/_chunk.py +0 -0
  16. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/_socket.py +0 -0
  17. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/_time.py +0 -0
  18. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/base.py +0 -0
  19. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/callback.py +0 -0
  20. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/clickhouse.py +0 -0
  21. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/datadog.py +0 -0
  22. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/elasticsearch.py +0 -0
  23. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/eventhubs.py +0 -0
  24. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/file.py +0 -0
  25. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/filtering.py +0 -0
  26. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/firehose.py +0 -0
  27. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/honeycomb.py +0 -0
  28. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/http.py +0 -0
  29. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/kafka.py +0 -0
  30. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/kinesis.py +0 -0
  31. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/logging_sink.py +0 -0
  32. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/logstash.py +0 -0
  33. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/loki.py +0 -0
  34. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/mongodb.py +0 -0
  35. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/multi.py +0 -0
  36. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/nats.py +0 -0
  37. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/newrelic.py +0 -0
  38. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/postgres.py +0 -0
  39. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/pubsub.py +0 -0
  40. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/rabbitmq.py +0 -0
  41. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/redis.py +0 -0
  42. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/sentry.py +0 -0
  43. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/sns.py +0 -0
  44. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/splunk.py +0 -0
  45. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/sqlite.py +0 -0
  46. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/sqs.py +0 -0
  47. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/stdout.py +0 -0
  48. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/syslog.py +0 -0
  49. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/transform.py +0 -0
  50. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/sinks/util.py +0 -0
  51. {log_foundry-0.3.1.dev1 → log_foundry-0.3.1.dev2}/src/log_foundry/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: log-foundry
3
- Version: 0.3.1.dev1
3
+ Version: 0.3.1.dev2
4
4
  Summary: Generate logs for your console and JSON events for downstream consumption.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -20,7 +20,7 @@ dependencies = [
20
20
  ]
21
21
 
22
22
  # Optional features. Install with: pip install log-foundry[aws]
23
- version = "0.3.1.dev1"
23
+ version = "0.3.1.dev2"
24
24
 
25
25
  [project.optional-dependencies]
26
26
  aws = ["boto3>=1.34"] # SQSSink, SNSSink, KinesisSink, FirehoseSink
@@ -39,7 +39,7 @@ from log_foundry.ids import (
39
39
  new_trace_id,
40
40
  parse_traceparent,
41
41
  )
42
- from log_foundry.model import Span, end_event, start_event
42
+ from log_foundry.model import Span, backfill_baggage, end_event, start_event
43
43
  from log_foundry.worker import Worker
44
44
 
45
45
  __all__ = ["trace", "continue_trace"]
@@ -245,8 +245,16 @@ def _flush(span: Span) -> None:
245
245
 
246
246
 
247
247
  def _close_span(span: Span, status: str, exc: BaseException | None) -> None:
248
- """Append the end event (so the flushed queue is complete), then flush."""
248
+ """Append the end event, complete the boundary events' baggage, then flush.
249
+
250
+ Every path — sync, async, and the error path — closes through here, which is what makes one
251
+ backfill call enough to cover all three.
252
+ """
249
253
  span.events.append(end_event(span, status, exc))
254
+ # SPEC-015: the boundary events were built with the baggage known at their construction —
255
+ # empty for `span.start`, which is buffered before the body runs. Complete them from the
256
+ # baggage live *now*, while the batch is still ours.
257
+ backfill_baggage(span, context.get_baggage())
250
258
  _flush(span)
251
259
 
252
260
 
@@ -13,7 +13,7 @@ import traceback
13
13
  from dataclasses import dataclass, field
14
14
  from datetime import datetime, timezone
15
15
 
16
- __all__ = ["Span", "build_event", "start_event", "end_event"]
16
+ __all__ = ["Span", "build_event", "start_event", "end_event", "backfill_baggage"]
17
17
 
18
18
  # Auto-generated span-boundary event messages. Tests assert on contract fields
19
19
  # (``status``, ``trace_id``), never on this text — rename freely.
@@ -104,3 +104,32 @@ def end_event(
104
104
  "stack": "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)),
105
105
  }
106
106
  return event
107
+
108
+
109
+ def backfill_baggage(span: Span, baggage: dict[str, object]) -> None:
110
+ """Merge the span's final baggage into its buffered **boundary** events.
111
+
112
+ ``@trace`` buffers ``span.start`` before the body runs, so baggage the body sets on its first
113
+ line did not exist when that event was built — and :func:`build_event` snapshots ``fields``
114
+ into each event dict, so a later value has to be written back. Same structural reason as
115
+ :func:`~log_foundry.decorator._reparent_current_span`. The whole span flushes as one batch at
116
+ close, so this completes the events before any of them is emitted.
117
+
118
+ Boundary events only. An ``info`` emitted before ``set_baggage`` genuinely did not carry it,
119
+ and rewriting a record of a moment would be a lie; merging over mid-span events would also let
120
+ baggage override a per-call field, inverting :func:`build_event`'s precedence. Boundary events
121
+ describe the span as a whole and carry no per-call fields, so baggage correctly wins there over
122
+ ``cfg.defaults`` and ``span.defaults``.
123
+
124
+ The baggage is a parameter rather than read from ``context``: this module does not know where
125
+ the current span lives (arch §6).
126
+ """
127
+ if not baggage:
128
+ return
129
+ for event in span.events:
130
+ # Matched on the message constants, not a position — that ``span.start`` is index 0 is an
131
+ # implementation detail of when it happens to be appended.
132
+ if event.get("message") in (_START_MESSAGE, _END_MESSAGE):
133
+ fields = event.get("fields")
134
+ if isinstance(fields, dict):
135
+ event["fields"] = {**fields, **baggage}