autotel-posthog 4.0.0 → 6.0.0

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.
package/README.md CHANGED
@@ -83,11 +83,13 @@ initFull({
83
83
  | `session.id` | `posthog.get_session_id()` | every span |
84
84
  | `user.id` | `posthog.get_distinct_id()` | every span |
85
85
  | `session.replay.url` | `posthog.get_session_replay_url({ withTimestamp: true })` | spans that recorded an error |
86
- | `feature_flag.<key>` | `posthog.getFeatureFlag(key)` | every span, for keys you name |
86
+ | `feature_flag.*` | `posthog.getFeatureFlag(key)` | every span, for keys you name |
87
87
 
88
88
  Identity is read when the span **starts**, not when it ends. PostHog rotates a session after 30 minutes idle and `identify()` can land mid-request; a long span asking at the end would be filed under whoever the visitor had become by then. The replay link is the one thing decided at the end, because only the end knows whether the span failed — and it is withheld if the session rotated in between, since the link would point at a recording the span has nothing to do with.
89
89
 
90
- A flag that evaluates to `false` is kept as a boolean: "not in the variant" is an answer, and comparing the two groups is the whole point. Only a flag PostHog has no opinion on is omitted.
90
+ Flags land under the **canonical** OpenTelemetry convention — `feature_flag.key`, `feature_flag.result.value`, `feature_flag.result.variant`, `feature_flag.provider.name`, `feature_flag.context.id` plus one `feature_flag.evaluation` event per flag, because span attributes hold a single flag and a second call would overwrite the first. That is what makes "error rate by variant" a query your backend already knows how to answer; an attribute keyed by flag name could not be grouped across flags, and nothing reads it.
91
+
92
+ A flag that evaluates to `false` is kept: "not in the variant" is an answer, and comparing the two groups is the whole point. Only a flag PostHog has no opinion on is omitted — recording that as `false` would make "off" and "unknown" the same reading.
91
93
 
92
94
  Use `spanEnrichers`, not `spanProcessor`. The latter _replaces_ the pipeline autotel builds, so passing an enricher there switches off the export you just configured.
93
95
 
package/dist/index.cjs CHANGED
@@ -1,4 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let autotel_web = require("autotel-web");
3
+ let autotel_feature_flags = require("autotel/feature-flags");
2
4
  let autotel_web_baggage = require("autotel-web/baggage");
3
5
  let _opentelemetry_api = require("@opentelemetry/api");
4
6
  //#region src/dev-mode.ts
@@ -155,8 +157,21 @@ function posthogCompatibility(options = {}) {
155
157
  const fill = (key, value) => {
156
158
  if (value !== void 0 && attributes[key] === void 0) span.setAttribute(key, value);
157
159
  };
158
- fill("user.id", readDistinctId(posthog));
159
- for (const key of options.featureFlags ?? []) fill(`feature_flag.${key}`, readFeatureFlag(posthog, key));
160
+ const distinctId = readDistinctId(posthog);
161
+ fill("user.id", distinctId);
162
+ for (const key of options.featureFlags ?? []) {
163
+ const value = readFeatureFlag(posthog, key);
164
+ if (value === void 0) continue;
165
+ (0, autotel_feature_flags.recordFeatureFlag)({
166
+ setAttributes: (attributes) => span.setAttributes(attributes),
167
+ track: autotel_web.emitEvent
168
+ }, {
169
+ key,
170
+ value,
171
+ provider: "posthog",
172
+ contextId: distinctId
173
+ });
174
+ }
160
175
  },
161
176
  /**
162
177
  * Only the replay link is left for the end, because only the end knows
package/dist/index.d.cts CHANGED
@@ -37,8 +37,10 @@ interface PostHogCompatibilityOptions {
37
37
  */
38
38
  posthog?: PostHogLike | (() => PostHogLike | undefined);
39
39
  /**
40
- * Flag keys to stamp on every span as `feature_flag.<key>`, so error rate and
41
- * latency can be split by variant in whichever backend receives the spans.
40
+ * Flag keys to record on every span, using the canonical OpenTelemetry
41
+ * `feature_flag.*` attributes and one `feature_flag.evaluation` event each
42
+ * so error rate and latency can be split by variant in whichever backend
43
+ * receives the spans, with no PostHog in the query path.
42
44
  *
43
45
  * Named explicitly rather than read wholesale: every flag is another
44
46
  * attribute on every span, and "all of them" is how an analytics convenience
package/dist/index.d.ts CHANGED
@@ -37,8 +37,10 @@ interface PostHogCompatibilityOptions {
37
37
  */
38
38
  posthog?: PostHogLike | (() => PostHogLike | undefined);
39
39
  /**
40
- * Flag keys to stamp on every span as `feature_flag.<key>`, so error rate and
41
- * latency can be split by variant in whichever backend receives the spans.
40
+ * Flag keys to record on every span, using the canonical OpenTelemetry
41
+ * `feature_flag.*` attributes and one `feature_flag.evaluation` event each
42
+ * so error rate and latency can be split by variant in whichever backend
43
+ * receives the spans, with no PostHog in the query path.
42
44
  *
43
45
  * Named explicitly rather than read wholesale: every flag is another
44
46
  * attribute on every span, and "all of them" is how an analytics convenience
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { emitEvent } from "autotel-web";
2
+ import { recordFeatureFlag } from "autotel/feature-flags";
1
3
  import { setBaggage } from "autotel-web/baggage";
2
4
  import { context, trace } from "@opentelemetry/api";
3
5
  //#region src/dev-mode.ts
@@ -154,8 +156,21 @@ function posthogCompatibility(options = {}) {
154
156
  const fill = (key, value) => {
155
157
  if (value !== void 0 && attributes[key] === void 0) span.setAttribute(key, value);
156
158
  };
157
- fill("user.id", readDistinctId(posthog));
158
- for (const key of options.featureFlags ?? []) fill(`feature_flag.${key}`, readFeatureFlag(posthog, key));
159
+ const distinctId = readDistinctId(posthog);
160
+ fill("user.id", distinctId);
161
+ for (const key of options.featureFlags ?? []) {
162
+ const value = readFeatureFlag(posthog, key);
163
+ if (value === void 0) continue;
164
+ recordFeatureFlag({
165
+ setAttributes: (attributes) => span.setAttributes(attributes),
166
+ track: emitEvent
167
+ }, {
168
+ key,
169
+ value,
170
+ provider: "posthog",
171
+ contextId: distinctId
172
+ });
173
+ }
159
174
  },
160
175
  /**
161
176
  * Only the replay link is left for the end, because only the end knows
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-posthog",
3
- "version": "4.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "Everything PostHog for autotel: browser session/replay join, server-side event subscriber, and trace links in both directions",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -30,9 +30,9 @@
30
30
  "@opentelemetry/sdk-trace-base": ">=2.0.0",
31
31
  "posthog-js": ">=1.200.0",
32
32
  "posthog-node": ">=4.0.0",
33
- "autotel": "7.3.0",
34
- "autotel-subscribers": "53.0.0",
35
- "autotel-web": "1.13.3"
33
+ "autotel": "7.5.0",
34
+ "autotel-subscribers": "55.0.0",
35
+ "autotel-web": "1.14.1"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@opentelemetry/context-async-hooks": "^2.10.0",
@@ -46,9 +46,9 @@
46
46
  "tsdown": "^0.22.14",
47
47
  "typescript": "^6.0.3",
48
48
  "vitest": "^4.1.10",
49
- "autotel": "7.3.0",
50
- "autotel-subscribers": "53.0.0",
51
- "autotel-web": "1.13.3"
49
+ "autotel": "7.5.0",
50
+ "autotel-subscribers": "55.0.0",
51
+ "autotel-web": "1.14.1"
52
52
  },
53
53
  "keywords": [
54
54
  "opentelemetry",