@mastra/posthog 0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939

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/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # @mastra/posthog
2
+
3
+ ## 0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939
4
+
5
+ ### Minor Changes
6
+
7
+ - Add PostHog AI observability exporter ([#10393](https://github.com/mastra-ai/mastra/pull/10393))
8
+
9
+ Adds a new PostHog exporter for AI tracing that sends spans to PostHog's LLM Analytics platform as structured events ($ai_generation and $ai_span). Features include:
10
+ - Event-based tracing architecture optimized for PostHog's AI analytics
11
+ - Support for privacy mode to exclude sensitive input/output data
12
+ - Serverless optimization with auto-configured batching
13
+ - Token usage normalization for AI SDK v4 and v5 formats
14
+ - Message format transformation for PostHog's strict API requirements
15
+ - 4-tier distinct ID resolution for user identification
16
+ - MODEL_CHUNK streaming event support
17
+ - Regional deployment support (US/EU/self-hosted)
18
+
19
+ ```typescript
20
+ import { Mastra } from '@mastra/core';
21
+ import { Observability } from '@mastra/observability';
22
+ import { PosthogExporter } from '@mastra/posthog';
23
+
24
+ const posthogExporter = new PosthogExporter({
25
+ apiKey: process.env.POSTHOG_API_KEY!,
26
+ });
27
+
28
+ const mastra = new Mastra({
29
+ observability: new Observability({
30
+ configs: {
31
+ posthog: {
32
+ serviceName: 'my-app',
33
+ exporters: [posthogExporter],
34
+ },
35
+ },
36
+ }),
37
+ });
38
+ ```
39
+
40
+ ### Patch Changes
41
+
42
+ - Updated dependencies [[`2319326`](https://github.com/mastra-ai/mastra/commit/2319326f8c64e503a09bbcf14be2dd65405445e0), [`39c9743`](https://github.com/mastra-ai/mastra/commit/39c97432d084294f8ba85fbf3ef28098ff21459e), [`f743dbb`](https://github.com/mastra-ai/mastra/commit/f743dbb8b40d1627b5c10c0e6fc154f4ebb6e394), [`fec5129`](https://github.com/mastra-ai/mastra/commit/fec5129de7fc64423ea03661a56cef31dc747a0d), [`0491e7c`](https://github.com/mastra-ai/mastra/commit/0491e7c9b714cb0ba22187ee062147ec2dd7c712), [`f6f4903`](https://github.com/mastra-ai/mastra/commit/f6f4903397314f73362061dc5a3e8e7c61ea34aa), [`0e8ed46`](https://github.com/mastra-ai/mastra/commit/0e8ed467c54d6901a6a365f270ec15d6faadb36c), [`6c049d9`](https://github.com/mastra-ai/mastra/commit/6c049d94063fdcbd5b81c4912a2bf82a92c9cc0b), [`910db9e`](https://github.com/mastra-ai/mastra/commit/910db9e0312888495eb5617b567f247d03303814), [`2f897df`](https://github.com/mastra-ai/mastra/commit/2f897df208508f46f51b7625e5dd20c37f93e0e3), [`d629361`](https://github.com/mastra-ai/mastra/commit/d629361a60f6565b5bfb11976fdaf7308af858e2), [`feb7ee4`](https://github.com/mastra-ai/mastra/commit/feb7ee4d09a75edb46c6669a3beaceec78811747), [`08c31c1`](https://github.com/mastra-ai/mastra/commit/08c31c188ebccd598acaf55e888b6397d01f7eae), [`3443770`](https://github.com/mastra-ai/mastra/commit/3443770662df8eb24c9df3589b2792d78cfcb811), [`f0a07e0`](https://github.com/mastra-ai/mastra/commit/f0a07e0111b3307c5fabfa4094c5c2cfb734fbe6), [`aaa40e7`](https://github.com/mastra-ai/mastra/commit/aaa40e788628b319baa8e889407d11ad626547fa), [`1521d71`](https://github.com/mastra-ai/mastra/commit/1521d716e5daedc74690c983fbd961123c56756b), [`9e1911d`](https://github.com/mastra-ai/mastra/commit/9e1911db2b4db85e0e768c3f15e0d61e319869f6), [`c456e01`](https://github.com/mastra-ai/mastra/commit/c456e0149e3c176afcefdbd9bb1d2c5917723725), [`ebac155`](https://github.com/mastra-ai/mastra/commit/ebac15564a590117db7078233f927a7e28a85106), [`dd1c38d`](https://github.com/mastra-ai/mastra/commit/dd1c38d1b75f1b695c27b40d8d9d6ed00d5e0f6f), [`5948e6a`](https://github.com/mastra-ai/mastra/commit/5948e6a5146c83666ba3f294b2be576c82a513fb), [`83b08dc`](https://github.com/mastra-ai/mastra/commit/83b08dcf1bfcc915efab23c09207df90fa247908), [`8940859`](https://github.com/mastra-ai/mastra/commit/89408593658199b4ad67f7b65e888f344e64a442), [`f0f8f12`](https://github.com/mastra-ai/mastra/commit/f0f8f125c308f2d0fd36942ef652fd852df7522f), [`e629310`](https://github.com/mastra-ai/mastra/commit/e629310f1a73fa236d49ec7a1d1cceb6229dc7cc), [`4c6b492`](https://github.com/mastra-ai/mastra/commit/4c6b492c4dd591c6a592520c1f6855d6e936d71f), [`dff01d8`](https://github.com/mastra-ai/mastra/commit/dff01d81ce1f4e4087cfac20fa868e6db138dd14), [`9d819d5`](https://github.com/mastra-ai/mastra/commit/9d819d54b61481639f4008e4694791bddf187edd), [`a64d16a`](https://github.com/mastra-ai/mastra/commit/a64d16aedafe57ee5707bdcc25f96e07fa1a0233), [`fd3d338`](https://github.com/mastra-ai/mastra/commit/fd3d338a2c362174ed5b383f1f011ad9fb0302aa), [`71c8d6c`](https://github.com/mastra-ai/mastra/commit/71c8d6c161253207b2b9588bdadb7eed604f7253), [`6179a9b`](https://github.com/mastra-ai/mastra/commit/6179a9ba36ffac326de3cc3c43cdc8028d37c251), [`c30400a`](https://github.com/mastra-ai/mastra/commit/c30400a49b994b1b97256fe785eb6c906fc2b232), [`00f4921`](https://github.com/mastra-ai/mastra/commit/00f4921dd2c91a1e5446799599ef7116a8214a1a), [`ca8041c`](https://github.com/mastra-ai/mastra/commit/ca8041cce0379fda22ed293a565bcb5b6ddca68a), [`7051bf3`](https://github.com/mastra-ai/mastra/commit/7051bf38b3b122a069008f861f7bfc004a6d9f6e), [`a8f1494`](https://github.com/mastra-ai/mastra/commit/a8f1494f4bbdc2770bcf327d4c7d869e332183f1), [`69e0a87`](https://github.com/mastra-ai/mastra/commit/69e0a878896a2da9494945d86e056a5f8f05b851), [`352a5d6`](https://github.com/mastra-ai/mastra/commit/352a5d625cfe09849b21e8f52a24c9f0366759d5), [`898a972`](https://github.com/mastra-ai/mastra/commit/898a9727d286c2510d6b702dfd367e6aaf5c6b0f), [`0793497`](https://github.com/mastra-ai/mastra/commit/079349753620c40246ffd673e3f9d7d9820beff3), [`a97003a`](https://github.com/mastra-ai/mastra/commit/a97003aa1cf2f4022a41912324a1e77263b326b8), [`01f8878`](https://github.com/mastra-ai/mastra/commit/01f88783de25e4de048c1c8aace43e26373c6ea5), [`5df9cce`](https://github.com/mastra-ai/mastra/commit/5df9cce1a753438413f64c11eeef8f845745c2a8), [`4c77209`](https://github.com/mastra-ai/mastra/commit/4c77209e6c11678808b365d545845918c40045c8), [`a854ede`](https://github.com/mastra-ai/mastra/commit/a854ede62bf5ac0945a624ac48913dd69c73aabf), [`c576fc0`](https://github.com/mastra-ai/mastra/commit/c576fc0b100b2085afded91a37c97a0ea0ec09c7), [`3defc80`](https://github.com/mastra-ai/mastra/commit/3defc80cf2b88a1b7fc1cc4ddcb91e982a614609), [`f111eac`](https://github.com/mastra-ai/mastra/commit/f111eac5de509b2e5fccfc1882e7f74cda264c74), [`00123ba`](https://github.com/mastra-ai/mastra/commit/00123ba96dc9e5cd0b110420ebdba56d8f237b25), [`16153fe`](https://github.com/mastra-ai/mastra/commit/16153fe7eb13c99401f48e6ca32707c965ee28b9), [`9f4a683`](https://github.com/mastra-ai/mastra/commit/9f4a6833e88b52574665c028fd5508ad5c2f6004), [`bc94344`](https://github.com/mastra-ai/mastra/commit/bc943444a1342d8a662151b7bce1df7dae32f59c), [`57d157f`](https://github.com/mastra-ai/mastra/commit/57d157f0b163a95c3e6c9eae31bdb11d1bfc64f9), [`903f67d`](https://github.com/mastra-ai/mastra/commit/903f67d184504a273893818c02b961f5423a79ad), [`d827d08`](https://github.com/mastra-ai/mastra/commit/d827d0808ffe1f3553a84e975806cc989b9735dd), [`2a90c55`](https://github.com/mastra-ai/mastra/commit/2a90c55a86a9210697d5adaab5ee94584b079adc), [`eb09742`](https://github.com/mastra-ai/mastra/commit/eb09742197f66c4c38154c3beec78313e69760b2), [`23c10a1`](https://github.com/mastra-ai/mastra/commit/23c10a1efdd9a693c405511ab2dc8a1236603162), [`96d35f6`](https://github.com/mastra-ai/mastra/commit/96d35f61376bc2b1bf148648a2c1985bd51bef55), [`5cbe88a`](https://github.com/mastra-ai/mastra/commit/5cbe88aefbd9f933bca669fd371ea36bf939ac6d), [`a1bd7b8`](https://github.com/mastra-ai/mastra/commit/a1bd7b8571db16b94eb01588f451a74758c96d65), [`d78b38d`](https://github.com/mastra-ai/mastra/commit/d78b38d898fce285260d3bbb4befade54331617f), [`a0a5b4b`](https://github.com/mastra-ai/mastra/commit/a0a5b4bbebe6c701ebbadf744873aa0d5ca01371), [`0633100`](https://github.com/mastra-ai/mastra/commit/0633100a911ad22f5256471bdf753da21c104742), [`c710c16`](https://github.com/mastra-ai/mastra/commit/c710c1652dccfdc4111c8412bca7a6bb1d48b441), [`354ad0b`](https://github.com/mastra-ai/mastra/commit/354ad0b7b1b8183ac567f236a884fc7ede6d7138), [`cfae733`](https://github.com/mastra-ai/mastra/commit/cfae73394f4920635e6c919c8e95ff9a0788e2e5), [`e3dfda7`](https://github.com/mastra-ai/mastra/commit/e3dfda7b11bf3b8c4bb55637028befb5f387fc74), [`69ea758`](https://github.com/mastra-ai/mastra/commit/69ea758358edd7117f191c2e69c8bb5fc79e7a1a), [`651e772`](https://github.com/mastra-ai/mastra/commit/651e772eb1475fb13e126d3fcc01751297a88214), [`993ad98`](https://github.com/mastra-ai/mastra/commit/993ad98d7ad3bebda9ecef5fec5c94349a0d04bc), [`676ccc7`](https://github.com/mastra-ai/mastra/commit/676ccc7fe92468d2d45d39c31a87825c89fd1ea0), [`3ff2c17`](https://github.com/mastra-ai/mastra/commit/3ff2c17a58e312fad5ea37377262c12d92ca0908), [`844ea5d`](https://github.com/mastra-ai/mastra/commit/844ea5dc0c248961e7bf73629ae7dcff503e853c), [`398fde3`](https://github.com/mastra-ai/mastra/commit/398fde3f39e707cda79372cdae8f9870e3b57c8d), [`c10398d`](https://github.com/mastra-ai/mastra/commit/c10398d5b88f1d4af556f4267ff06f1d11e89179), [`f0f8f12`](https://github.com/mastra-ai/mastra/commit/f0f8f125c308f2d0fd36942ef652fd852df7522f), [`b61b93f`](https://github.com/mastra-ai/mastra/commit/b61b93f9e058b11dd2eec169853175d31dbdd567), [`bae33d9`](https://github.com/mastra-ai/mastra/commit/bae33d91a63fbb64d1e80519e1fc1acaed1e9013), [`0d7618b`](https://github.com/mastra-ai/mastra/commit/0d7618bc650bf2800934b243eca5648f4aeed9c2), [`7b763e5`](https://github.com/mastra-ai/mastra/commit/7b763e52fc3eaf699c2a99f2adf418dd46e4e9a5), [`d36cfbb`](https://github.com/mastra-ai/mastra/commit/d36cfbbb6565ba5f827883cc9bb648eb14befdc1), [`3697853`](https://github.com/mastra-ai/mastra/commit/3697853deeb72017d90e0f38a93c1e29221aeca0), [`b2e45ec`](https://github.com/mastra-ai/mastra/commit/b2e45eca727a8db01a81ba93f1a5219c7183c839), [`43ca8f2`](https://github.com/mastra-ai/mastra/commit/43ca8f2c7334851cc7b4d3d2f037d8784bfbdd5f), [`d6d49f7`](https://github.com/mastra-ai/mastra/commit/d6d49f7b8714fa19a52ff9c7cf7fb7e73751901e), [`00c2387`](https://github.com/mastra-ai/mastra/commit/00c2387f5f04a365316f851e58666ac43f8c4edf), [`a534e95`](https://github.com/mastra-ai/mastra/commit/a534e9591f83b3cc1ebff99c67edf4cda7bf81d3), [`9d0e7fe`](https://github.com/mastra-ai/mastra/commit/9d0e7feca8ed98de959f53476ee1456073673348), [`53d927c`](https://github.com/mastra-ai/mastra/commit/53d927cc6f03bff33655b7e2b788da445a08731d), [`ad6250d`](https://github.com/mastra-ai/mastra/commit/ad6250dbdaad927e29f74a27b83f6c468b50a705), [`3f2faf2`](https://github.com/mastra-ai/mastra/commit/3f2faf2e2d685d6c053cc5af1bf9fedf267b2ce5), [`22f64bc`](https://github.com/mastra-ai/mastra/commit/22f64bc1d37149480b58bf2fefe35b79a1e3e7d5), [`3a73998`](https://github.com/mastra-ai/mastra/commit/3a73998fa4ebeb7f3dc9301afe78095fc63e7999), [`83d5942`](https://github.com/mastra-ai/mastra/commit/83d5942669ce7bba4a6ca4fd4da697a10eb5ebdc), [`b7959e6`](https://github.com/mastra-ai/mastra/commit/b7959e6e25a46b480f9ea2217c4c6c588c423791), [`bda6370`](https://github.com/mastra-ai/mastra/commit/bda637009360649aaf579919e7873e33553c273e), [`d7acd8e`](https://github.com/mastra-ai/mastra/commit/d7acd8e987b5d7eff4fd98b0906c17c06a2e83d5), [`c7f1f7d`](https://github.com/mastra-ai/mastra/commit/c7f1f7d24f61f247f018cc2d1f33bf63212959a7), [`0bddc6d`](https://github.com/mastra-ai/mastra/commit/0bddc6d8dbd6f6008c0cba2e4960a2da75a55af1), [`735d8c1`](https://github.com/mastra-ai/mastra/commit/735d8c1c0d19fbc09e6f8b66cf41bc7655993838), [`acf322e`](https://github.com/mastra-ai/mastra/commit/acf322e0f1fd0189684cf529d91c694bea918a45), [`2ca67cc`](https://github.com/mastra-ai/mastra/commit/2ca67cc3bb1f6a617353fdcab197d9efebe60d6f), [`e16d553`](https://github.com/mastra-ai/mastra/commit/e16d55338403c7553531cc568125c63d53653dff), [`c942802`](https://github.com/mastra-ai/mastra/commit/c942802a477a925b01859a7b8688d4355715caaa), [`a0c8c1b`](https://github.com/mastra-ai/mastra/commit/a0c8c1b87d4fee252aebda73e8637fbe01d761c9), [`cc34739`](https://github.com/mastra-ai/mastra/commit/cc34739c34b6266a91bea561119240a7acf47887), [`c218bd3`](https://github.com/mastra-ai/mastra/commit/c218bd3759e32423735b04843a09404572631014), [`9e67002`](https://github.com/mastra-ai/mastra/commit/9e67002b52c9be19936c420a489dbee9c5fd6a78), [`2c4438b`](https://github.com/mastra-ai/mastra/commit/2c4438b87817ab7eed818c7990fef010475af1a3), [`35edc49`](https://github.com/mastra-ai/mastra/commit/35edc49ac0556db609189641d6341e76771b81fc), [`4d59f58`](https://github.com/mastra-ai/mastra/commit/4d59f58de2d90d6e2810a19d4518e38ddddb9038), [`2b8893c`](https://github.com/mastra-ai/mastra/commit/2b8893cb108ef9acb72ee7835cd625610d2c1a4a), [`8e5c75b`](https://github.com/mastra-ai/mastra/commit/8e5c75bdb1d08a42d45309a4c72def4b6890230f), [`e1bb9c9`](https://github.com/mastra-ai/mastra/commit/e1bb9c94b4eb68b019ae275981be3feb769b5365), [`351a11f`](https://github.com/mastra-ai/mastra/commit/351a11fcaf2ed1008977fa9b9a489fc422e51cd4), [`e59e0d3`](https://github.com/mastra-ai/mastra/commit/e59e0d32afb5fcf2c9f3c00c8f81f6c21d3a63fa), [`465ac05`](https://github.com/mastra-ai/mastra/commit/465ac0526a91d175542091c675181f1a96c98c46), [`fa8409b`](https://github.com/mastra-ai/mastra/commit/fa8409bc39cfd8ba6643b9db5269b90b22e2a2f7), [`e7266a2`](https://github.com/mastra-ai/mastra/commit/e7266a278db02035c97a5e9cd9d1669a6b7a535d), [`173c535`](https://github.com/mastra-ai/mastra/commit/173c535c0645b0da404fe09f003778f0b0d4e019)]:
43
+ - @mastra/core@0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939
44
+ - @mastra/observability@0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939
package/LICENSE.md ADDED
@@ -0,0 +1,15 @@
1
+ # Apache License 2.0
2
+
3
+ Copyright (c) 2025 Kepler Software, Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # @mastra/posthog
2
+
3
+ PostHog AI Observability exporter for Mastra applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mastra/posthog
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { PosthogExporter } from '@mastra/posthog';
15
+
16
+ // Use with Mastra
17
+ const mastra = new Mastra({
18
+ ...,
19
+ observability: {
20
+ configs: {
21
+ posthog: {
22
+ serviceName: 'service',
23
+ exporters: [
24
+ new PosthogExporter({
25
+ apiKey: process.env.POSTHOG_API_KEY,
26
+ host: 'https://us.i.posthog.com', // optional, defaults to US region
27
+ }),
28
+ ],
29
+ },
30
+ },
31
+ },
32
+ });
33
+ ```
34
+
35
+ ## Features
36
+
37
+ ### AI Tracing
38
+
39
+ - **Event-based architecture**: Captures LLM calls and operations as PostHog events
40
+ - **LLM analytics**: Automatic tracking of token usage, latency, and costs
41
+ - **Streaming support**: Handles streaming LLM responses with MODEL_CHUNK events
42
+ - **Privacy mode**: Optional exclusion of input/output data for sensitive applications
43
+ - **Serverless optimized**: Auto-configures batching for serverless environments
44
+
45
+ ### Supported Event Types
46
+
47
+ - `$ai_generation`: LLM model calls (MODEL_GENERATION, MODEL_STEP)
48
+ - `$ai_span`: Operations like tool calls, workflows, and streaming chunks
49
+ - Hierarchical traces with parent-child relationships via `$ai_parent_id`
50
+ - Session grouping with `$ai_session_id`
51
+
52
+ ## Configuration
53
+
54
+ ### Basic Configuration
55
+
56
+ ```typescript
57
+ new PosthogExporter({
58
+ apiKey: process.env.POSTHOG_API_KEY,
59
+ });
60
+ ```
61
+
62
+ ### Advanced Configuration
63
+
64
+ ```typescript
65
+ new PosthogExporter({
66
+ // Required
67
+ apiKey: process.env.POSTHOG_API_KEY,
68
+
69
+ // Optional: Region/Host
70
+ host: 'https://eu.i.posthog.com', // EU region
71
+ // or
72
+ host: 'https://your-instance.com', // Self-hosted
73
+
74
+ // Optional: Batching (defaults: flushAt=20, flushInterval=10000)
75
+ flushAt: 20, // Batch size before auto-flush
76
+ flushInterval: 10000, // Flush interval in milliseconds
77
+
78
+ // Optional: Serverless mode (auto-configures smaller batches)
79
+ serverless: true, // Sets flushAt=10, flushInterval=2000
80
+
81
+ // Optional: User identification
82
+ defaultDistinctId: 'anonymous', // Fallback if no userId in metadata
83
+
84
+ // Optional: Privacy
85
+ enablePrivacyMode: false, // Set to true to exclude input/output from LLM events
86
+ });
87
+ ```
88
+
89
+ ### Serverless Environments
90
+
91
+ When deploying to serverless environments (Lambda, Vercel Functions, etc.), enable serverless mode:
92
+
93
+ ```typescript
94
+ new PosthogExporter({
95
+ apiKey: process.env.POSTHOG_API_KEY,
96
+ serverless: true, // Auto-configures for serverless
97
+ });
98
+ ```
99
+
100
+ **Important**: Always call `await mastra.shutdown()` before your serverless function exits to flush remaining events.
101
+
102
+ ### Privacy Mode
103
+
104
+ To exclude sensitive input/output data while still tracking token usage and latency:
105
+
106
+ ```typescript
107
+ new PosthogExporter({
108
+ apiKey: process.env.POSTHOG_API_KEY,
109
+ enablePrivacyMode: true, // Excludes $ai_input and $ai_output_choices
110
+ });
111
+ ```
112
+
113
+ Note: Privacy mode only applies to `$ai_generation` events. Span events (tool calls, etc.) still include input/output state.
114
+
115
+ ## Metadata
116
+
117
+ Include metadata in your Mastra spans to enrich PostHog events:
118
+
119
+ ```typescript
120
+ // User identification
121
+ {
122
+ metadata: {
123
+ userId: 'user-123', // → distinctId in PostHog
124
+ sessionId: 'session-abc', // → $ai_session_id for grouping
125
+
126
+ // Custom properties (passed through to PostHog)
127
+ environment: 'production',
128
+ version: '1.0.0',
129
+ }
130
+ }
131
+ ```
132
+
133
+ ## Cost Tracking
134
+
135
+ PostHog automatically calculates costs from:
136
+
137
+ - Model name + token counts (uses OpenRouter pricing data)
138
+ - Or you can send pre-calculated costs in span attributes
139
+
140
+ ## Viewing Data in PostHog
141
+
142
+ 1. Navigate to **Product Analytics** → **Events**
143
+ 2. Filter for events starting with `$ai_`
144
+ 3. Use the **AI Observability** dashboard (if available in your PostHog plan)
145
+ 4. Query events by:
146
+ - `$ai_trace_id`: Group all events in a trace
147
+ - `$ai_session_id`: Group traces in a session
148
+ - `$ai_model`: Filter by model (e.g., "gpt-4o")
149
+ - `$ai_provider`: Filter by provider (e.g., "openai")
150
+
151
+ ## Environment Variables
152
+
153
+ ```bash
154
+ # Required
155
+ POSTHOG_API_KEY=phc_...
156
+
157
+ # Optional
158
+ POSTHOG_HOST=https://us.i.posthog.com # or eu.i.posthog.com
159
+ ```
160
+
161
+ ## Links
162
+
163
+ - [PostHog LLM Analytics Documentation](https://posthog.com/docs/ai-engineering/langchain-integration)
164
+ - [Mastra Observability Documentation](https://mastra.ai/docs/observability)
package/dist/index.cjs ADDED
@@ -0,0 +1,292 @@
1
+ 'use strict';
2
+
3
+ var observability$1 = require('@mastra/core/observability');
4
+ var observability = require('@mastra/observability');
5
+ var posthogNode = require('posthog-node');
6
+
7
+ // src/tracing.ts
8
+ var PosthogExporter = class _PosthogExporter extends observability.BaseExporter {
9
+ name = "posthog";
10
+ client;
11
+ config;
12
+ traceMap = /* @__PURE__ */ new Map();
13
+ static SERVERLESS_FLUSH_AT = 10;
14
+ static SERVERLESS_FLUSH_INTERVAL = 2e3;
15
+ static DEFAULT_FLUSH_AT = 20;
16
+ static DEFAULT_FLUSH_INTERVAL = 1e4;
17
+ constructor(config) {
18
+ super(config);
19
+ this.config = config;
20
+ if (!config.apiKey) {
21
+ this.setDisabled("Missing required API key");
22
+ this.client = null;
23
+ return;
24
+ }
25
+ const clientConfig = this.buildClientConfig(config);
26
+ this.client = new posthogNode.PostHog(config.apiKey, clientConfig);
27
+ this.logInitialization(config.serverless ?? false, clientConfig);
28
+ }
29
+ buildClientConfig(config) {
30
+ const isServerless = config.serverless ?? false;
31
+ const flushAt = config.flushAt ?? (isServerless ? _PosthogExporter.SERVERLESS_FLUSH_AT : _PosthogExporter.DEFAULT_FLUSH_AT);
32
+ const flushInterval = config.flushInterval ?? (isServerless ? _PosthogExporter.SERVERLESS_FLUSH_INTERVAL : _PosthogExporter.DEFAULT_FLUSH_INTERVAL);
33
+ const host = config.host || process.env.POSTHOG_HOST || "https://us.i.posthog.com";
34
+ if (!config.host && !process.env.POSTHOG_HOST) {
35
+ this.logger.warn(
36
+ 'No PostHog host specified, using US default (https://us.i.posthog.com). For EU region, set `host: "https://eu.i.posthog.com"` in config or POSTHOG_HOST env var. For self-hosted, provide your instance URL.'
37
+ );
38
+ }
39
+ return {
40
+ host,
41
+ flushAt,
42
+ flushInterval,
43
+ privacyMode: config.enablePrivacyMode
44
+ };
45
+ }
46
+ logInitialization(isServerless, config) {
47
+ const message = isServerless ? "PostHog exporter initialized in serverless mode" : "PostHog exporter initialized";
48
+ this.logger.info(message, config);
49
+ }
50
+ async _exportTracingEvent(event) {
51
+ if (!this.client) return;
52
+ try {
53
+ if (event.exportedSpan.isEvent) {
54
+ if (event.type === "span_started") {
55
+ await this.captureEventSpan(event.exportedSpan);
56
+ }
57
+ return;
58
+ }
59
+ switch (event.type) {
60
+ case "span_started":
61
+ await this.handleSpanStarted(event.exportedSpan);
62
+ break;
63
+ case "span_updated":
64
+ break;
65
+ case "span_ended":
66
+ await this.handleSpanEnded(event.exportedSpan);
67
+ break;
68
+ }
69
+ } catch (error) {
70
+ this.logger.error("PostHog exporter error", { error, event });
71
+ }
72
+ }
73
+ async handleSpanStarted(span) {
74
+ let traceData = this.traceMap.get(span.traceId);
75
+ if (!traceData) {
76
+ traceData = {
77
+ spans: /* @__PURE__ */ new Map(),
78
+ distinctId: void 0
79
+ };
80
+ this.traceMap.set(span.traceId, traceData);
81
+ }
82
+ traceData.spans.set(span.id, {
83
+ startTime: this.toDate(span.startTime),
84
+ type: span.type
85
+ });
86
+ if (!traceData.distinctId) {
87
+ const userId = span.metadata?.userId;
88
+ if (userId) {
89
+ traceData.distinctId = String(userId);
90
+ }
91
+ }
92
+ }
93
+ async handleSpanEnded(span) {
94
+ const traceData = this.traceMap.get(span.traceId);
95
+ if (!traceData) {
96
+ this.logger.warn(`Trace data not found for ended span: ${span.id}`);
97
+ return;
98
+ }
99
+ const cachedSpan = traceData.spans.get(span.id);
100
+ if (!cachedSpan) {
101
+ this.logger.warn(`Span cache not found for ended span: ${span.id}`);
102
+ return;
103
+ }
104
+ const startTime = cachedSpan.startTime.getTime();
105
+ const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();
106
+ const latency = (endTime - startTime) / 1e3;
107
+ const eventName = this.mapToPostHogEvent(span.type);
108
+ const distinctId = this.getDistinctId(span, traceData);
109
+ const properties = this.buildEventProperties(span, latency);
110
+ this.client.capture({
111
+ distinctId,
112
+ event: eventName,
113
+ properties,
114
+ timestamp: new Date(endTime)
115
+ });
116
+ traceData.spans.delete(span.id);
117
+ if (traceData.spans.size === 0) {
118
+ this.traceMap.delete(span.traceId);
119
+ }
120
+ }
121
+ async captureEventSpan(span) {
122
+ const eventName = this.mapToPostHogEvent(span.type);
123
+ const traceData = this.traceMap.get(span.traceId);
124
+ const distinctId = this.getDistinctId(span, traceData);
125
+ const properties = this.buildEventProperties(span, 0);
126
+ this.client.capture({
127
+ distinctId,
128
+ event: eventName,
129
+ properties,
130
+ timestamp: span.endTime ? new Date(span.endTime) : /* @__PURE__ */ new Date()
131
+ });
132
+ }
133
+ async shutdown() {
134
+ if (this.client) {
135
+ await this.client.shutdown();
136
+ }
137
+ this.traceMap.clear();
138
+ await super.shutdown();
139
+ this.logger.info("PostHog exporter shutdown complete");
140
+ }
141
+ toDate(timestamp) {
142
+ return timestamp instanceof Date ? timestamp : new Date(timestamp);
143
+ }
144
+ mapToPostHogEvent(spanType) {
145
+ switch (spanType) {
146
+ case observability$1.SpanType.MODEL_GENERATION:
147
+ case observability$1.SpanType.MODEL_STEP:
148
+ return "$ai_generation";
149
+ case observability$1.SpanType.MODEL_CHUNK:
150
+ case observability$1.SpanType.TOOL_CALL:
151
+ case observability$1.SpanType.MCP_TOOL_CALL:
152
+ case observability$1.SpanType.PROCESSOR_RUN:
153
+ case observability$1.SpanType.AGENT_RUN:
154
+ case observability$1.SpanType.WORKFLOW_RUN:
155
+ case observability$1.SpanType.GENERIC:
156
+ default:
157
+ return "$ai_span";
158
+ }
159
+ }
160
+ getDistinctId(span, traceData) {
161
+ if (span.metadata?.userId) {
162
+ return String(span.metadata.userId);
163
+ }
164
+ if (traceData?.distinctId) {
165
+ return traceData.distinctId;
166
+ }
167
+ if (this.config.defaultDistinctId) {
168
+ return this.config.defaultDistinctId;
169
+ }
170
+ return "anonymous";
171
+ }
172
+ buildEventProperties(span, latency) {
173
+ const baseProperties = {
174
+ $ai_trace_id: span.traceId,
175
+ $ai_latency: latency,
176
+ $ai_is_error: !!span.errorInfo
177
+ };
178
+ if (span.parentSpanId) {
179
+ baseProperties.$ai_parent_id = span.parentSpanId;
180
+ }
181
+ if (span.metadata?.sessionId) {
182
+ baseProperties.$ai_session_id = span.metadata.sessionId;
183
+ }
184
+ if (span.type === observability$1.SpanType.MODEL_GENERATION || span.type === observability$1.SpanType.MODEL_STEP) {
185
+ baseProperties.$ai_generation_id = span.id;
186
+ return { ...baseProperties, ...this.buildGenerationProperties(span) };
187
+ } else {
188
+ baseProperties.$ai_span_id = span.id;
189
+ baseProperties.$ai_span_name = span.name;
190
+ return { ...baseProperties, ...this.buildSpanProperties(span) };
191
+ }
192
+ }
193
+ extractErrorProperties(span) {
194
+ if (!span.errorInfo) {
195
+ return {};
196
+ }
197
+ const props = {
198
+ error_message: span.errorInfo.message
199
+ };
200
+ if (span.errorInfo.id) {
201
+ props.error_id = span.errorInfo.id;
202
+ }
203
+ if (span.errorInfo.category) {
204
+ props.error_category = span.errorInfo.category;
205
+ }
206
+ return props;
207
+ }
208
+ extractCustomMetadata(span) {
209
+ const { userId, sessionId, ...customMetadata } = span.metadata ?? {};
210
+ return customMetadata;
211
+ }
212
+ buildGenerationProperties(span) {
213
+ const props = {};
214
+ const attrs = span.attributes ?? {};
215
+ props.$ai_model = attrs.model || "unknown-model";
216
+ props.$ai_provider = attrs.provider || "unknown-provider";
217
+ if (span.input) props.$ai_input = this.formatMessages(span.input, "user");
218
+ if (span.output) props.$ai_output_choices = this.formatMessages(span.output, "assistant");
219
+ if (attrs.usage) {
220
+ const { usage } = attrs;
221
+ const inputTokens = usage.inputTokens ?? usage.promptTokens;
222
+ const outputTokens = usage.outputTokens ?? usage.completionTokens;
223
+ const totalTokens = usage.totalTokens;
224
+ if (inputTokens !== void 0) props.$ai_input_tokens = inputTokens;
225
+ if (outputTokens !== void 0) props.$ai_output_tokens = outputTokens;
226
+ if (totalTokens !== void 0) props.$ai_total_tokens = totalTokens;
227
+ if (usage.reasoningTokens !== void 0) props.reasoning_tokens = usage.reasoningTokens;
228
+ if (usage.cachedInputTokens !== void 0) props.cached_input_tokens = usage.cachedInputTokens;
229
+ }
230
+ if (attrs.parameters) {
231
+ if (attrs.parameters.temperature !== void 0) props.$ai_temperature = attrs.parameters.temperature;
232
+ if (attrs.parameters.maxOutputTokens !== void 0) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;
233
+ }
234
+ if (attrs.streaming !== void 0) props.$ai_stream = attrs.streaming;
235
+ return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };
236
+ }
237
+ buildSpanProperties(span) {
238
+ const props = {};
239
+ if (span.input) props.$ai_input_state = span.input;
240
+ if (span.output) props.$ai_output_state = span.output;
241
+ if (span.type === observability$1.SpanType.MODEL_CHUNK) {
242
+ const attrs = span.attributes;
243
+ if (attrs?.chunkType) props.chunk_type = attrs.chunkType;
244
+ if (attrs?.sequenceNumber !== void 0) props.chunk_sequence_number = attrs.sequenceNumber;
245
+ }
246
+ if (span.attributes) {
247
+ Object.assign(props, span.attributes);
248
+ }
249
+ return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };
250
+ }
251
+ formatMessages(data, defaultRole = "user") {
252
+ if (this.isMessageArray(data)) {
253
+ return data.map((msg) => this.normalizeMessage(msg));
254
+ }
255
+ if (typeof data === "string") {
256
+ return [{ role: defaultRole, content: [{ type: "text", text: data }] }];
257
+ }
258
+ return [{ role: defaultRole, content: [{ type: "text", text: this.safeStringify(data) }] }];
259
+ }
260
+ isMessageArray(data) {
261
+ if (!Array.isArray(data) || data.length === 0) {
262
+ return false;
263
+ }
264
+ return data.every((item) => typeof item === "object" && item !== null && "role" in item && "content" in item);
265
+ }
266
+ normalizeMessage(msg) {
267
+ if (typeof msg.content === "string") {
268
+ return {
269
+ role: msg.role,
270
+ content: [{ type: "text", text: msg.content }]
271
+ };
272
+ }
273
+ return {
274
+ role: msg.role,
275
+ content: msg.content
276
+ };
277
+ }
278
+ safeStringify(data) {
279
+ try {
280
+ return JSON.stringify(data);
281
+ } catch {
282
+ if (typeof data === "object" && data !== null) {
283
+ return `[Non-serializable ${data.constructor?.name || "Object"}]`;
284
+ }
285
+ return String(data);
286
+ }
287
+ }
288
+ };
289
+
290
+ exports.PosthogExporter = PosthogExporter;
291
+ //# sourceMappingURL=index.cjs.map
292
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tracing.ts"],"names":["BaseExporter","PostHog","SpanType"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { TracingEvent, AnyExportedSpan, ModelGenerationAttributes } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport { BaseExporter } from '@mastra/observability';\nimport { PostHog } from 'posthog-node';\n\ninterface PostHogMessage {\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: PostHogContent[];\n}\n\ninterface PostHogContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ninterface MastraMessage {\n role: string;\n content: string | MastraContent[];\n}\n\ninterface MastraContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ntype SpanData = string | MastraMessage[] | Record<string, unknown> | unknown;\n\nexport interface PosthogExporterConfig extends BaseExporterConfig {\n apiKey: string;\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n serverless?: boolean;\n defaultDistinctId?: string;\n enablePrivacyMode?: boolean;\n}\n\ntype SpanCache = {\n startTime: Date;\n type: SpanType;\n};\n\ntype TraceMetadata = {\n spans: Map<string, SpanCache>;\n distinctId?: string;\n};\n\nexport class PosthogExporter extends BaseExporter {\n name = 'posthog';\n private client: PostHog;\n private config: PosthogExporterConfig;\n private traceMap = new Map<string, TraceMetadata>();\n\n private static readonly SERVERLESS_FLUSH_AT = 10;\n private static readonly SERVERLESS_FLUSH_INTERVAL = 2000;\n private static readonly DEFAULT_FLUSH_AT = 20;\n private static readonly DEFAULT_FLUSH_INTERVAL = 10000;\n\n constructor(config: PosthogExporterConfig) {\n super(config);\n this.config = config;\n\n if (!config.apiKey) {\n this.setDisabled('Missing required API key');\n this.client = null as any;\n return;\n }\n\n const clientConfig = this.buildClientConfig(config);\n this.client = new PostHog(config.apiKey, clientConfig);\n this.logInitialization(config.serverless ?? false, clientConfig);\n }\n\n private buildClientConfig(config: PosthogExporterConfig): {\n host: string;\n flushAt: number;\n flushInterval: number;\n privacyMode?: boolean;\n } {\n const isServerless = config.serverless ?? false;\n const flushAt =\n config.flushAt ?? (isServerless ? PosthogExporter.SERVERLESS_FLUSH_AT : PosthogExporter.DEFAULT_FLUSH_AT);\n const flushInterval =\n config.flushInterval ??\n (isServerless ? PosthogExporter.SERVERLESS_FLUSH_INTERVAL : PosthogExporter.DEFAULT_FLUSH_INTERVAL);\n\n const host = config.host || process.env.POSTHOG_HOST || 'https://us.i.posthog.com';\n\n if (!config.host && !process.env.POSTHOG_HOST) {\n this.logger.warn(\n 'No PostHog host specified, using US default (https://us.i.posthog.com). ' +\n 'For EU region, set `host: \"https://eu.i.posthog.com\"` in config or POSTHOG_HOST env var. ' +\n 'For self-hosted, provide your instance URL.',\n );\n }\n\n return {\n host,\n flushAt,\n flushInterval,\n privacyMode: config.enablePrivacyMode,\n };\n }\n\n private logInitialization(\n isServerless: boolean,\n config: { host: string; flushAt: number; flushInterval: number },\n ): void {\n const message = isServerless ? 'PostHog exporter initialized in serverless mode' : 'PostHog exporter initialized';\n\n this.logger.info(message, config);\n }\n\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (!this.client) return;\n\n try {\n if (event.exportedSpan.isEvent) {\n if (event.type === 'span_started') {\n await this.captureEventSpan(event.exportedSpan);\n }\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.exportedSpan);\n break;\n case 'span_updated':\n break;\n case 'span_ended':\n await this.handleSpanEnded(event.exportedSpan);\n break;\n }\n } catch (error) {\n this.logger.error('PostHog exporter error', { error, event });\n }\n }\n\n private async handleSpanStarted(span: AnyExportedSpan): Promise<void> {\n let traceData = this.traceMap.get(span.traceId);\n\n if (!traceData) {\n traceData = {\n spans: new Map(),\n distinctId: undefined,\n };\n this.traceMap.set(span.traceId, traceData);\n }\n\n traceData.spans.set(span.id, {\n startTime: this.toDate(span.startTime),\n type: span.type,\n });\n\n if (!traceData.distinctId) {\n const userId = span.metadata?.userId;\n if (userId) {\n traceData.distinctId = String(userId);\n }\n }\n }\n\n private async handleSpanEnded(span: AnyExportedSpan): Promise<void> {\n const traceData = this.traceMap.get(span.traceId);\n\n if (!traceData) {\n this.logger.warn(`Trace data not found for ended span: ${span.id}`);\n return;\n }\n\n const cachedSpan = traceData.spans.get(span.id);\n if (!cachedSpan) {\n this.logger.warn(`Span cache not found for ended span: ${span.id}`);\n return;\n }\n\n const startTime = cachedSpan.startTime.getTime();\n const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();\n const latency = (endTime - startTime) / 1000;\n\n const eventName = this.mapToPostHogEvent(span.type);\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, latency);\n\n this.client.capture({\n distinctId,\n event: eventName,\n properties,\n timestamp: new Date(endTime),\n });\n\n traceData.spans.delete(span.id);\n if (traceData.spans.size === 0) {\n this.traceMap.delete(span.traceId);\n }\n }\n\n private async captureEventSpan(span: AnyExportedSpan): Promise<void> {\n const eventName = this.mapToPostHogEvent(span.type);\n const traceData = this.traceMap.get(span.traceId);\n\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, 0);\n\n this.client.capture({\n distinctId,\n event: eventName,\n properties,\n timestamp: span.endTime ? new Date(span.endTime) : new Date(),\n });\n }\n\n async shutdown(): Promise<void> {\n if (this.client) {\n await this.client.shutdown();\n }\n this.traceMap.clear();\n await super.shutdown();\n this.logger.info('PostHog exporter shutdown complete');\n }\n\n private toDate(timestamp: Date | number): Date {\n return timestamp instanceof Date ? timestamp : new Date(timestamp);\n }\n\n private mapToPostHogEvent(spanType: SpanType): string {\n switch (spanType) {\n case SpanType.MODEL_GENERATION:\n case SpanType.MODEL_STEP:\n return '$ai_generation';\n case SpanType.MODEL_CHUNK:\n case SpanType.TOOL_CALL:\n case SpanType.MCP_TOOL_CALL:\n case SpanType.PROCESSOR_RUN:\n case SpanType.AGENT_RUN:\n case SpanType.WORKFLOW_RUN:\n case SpanType.GENERIC:\n default:\n return '$ai_span';\n }\n }\n\n private getDistinctId(span: AnyExportedSpan, traceData?: TraceMetadata): string {\n if (span.metadata?.userId) {\n return String(span.metadata.userId);\n }\n\n if (traceData?.distinctId) {\n return traceData.distinctId;\n }\n\n if (this.config.defaultDistinctId) {\n return this.config.defaultDistinctId;\n }\n\n return 'anonymous';\n }\n\n private buildEventProperties(span: AnyExportedSpan, latency: number): Record<string, any> {\n const baseProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_latency: latency,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.parentSpanId) {\n baseProperties.$ai_parent_id = span.parentSpanId;\n }\n\n if (span.metadata?.sessionId) {\n baseProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {\n baseProperties.$ai_generation_id = span.id;\n return { ...baseProperties, ...this.buildGenerationProperties(span) };\n } else {\n baseProperties.$ai_span_id = span.id;\n baseProperties.$ai_span_name = span.name;\n return { ...baseProperties, ...this.buildSpanProperties(span) };\n }\n }\n\n private extractErrorProperties(span: AnyExportedSpan): Record<string, any> {\n if (!span.errorInfo) {\n return {};\n }\n\n const props: Record<string, string> = {\n error_message: span.errorInfo.message,\n };\n\n if (span.errorInfo.id) {\n props.error_id = span.errorInfo.id;\n }\n\n if (span.errorInfo.category) {\n props.error_category = span.errorInfo.category;\n }\n\n return props;\n }\n\n private extractCustomMetadata(span: AnyExportedSpan): Record<string, any> {\n const { userId, sessionId, ...customMetadata } = span.metadata ?? {};\n return customMetadata;\n }\n\n private buildGenerationProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n const attrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n props.$ai_model = attrs.model || 'unknown-model';\n props.$ai_provider = attrs.provider || 'unknown-provider';\n\n if (span.input) props.$ai_input = this.formatMessages(span.input, 'user');\n if (span.output) props.$ai_output_choices = this.formatMessages(span.output, 'assistant');\n\n if (attrs.usage) {\n const { usage } = attrs;\n const inputTokens = usage.inputTokens ?? usage.promptTokens;\n const outputTokens = usage.outputTokens ?? usage.completionTokens;\n const totalTokens = usage.totalTokens;\n\n if (inputTokens !== undefined) props.$ai_input_tokens = inputTokens;\n if (outputTokens !== undefined) props.$ai_output_tokens = outputTokens;\n if (totalTokens !== undefined) props.$ai_total_tokens = totalTokens;\n\n if (usage.reasoningTokens !== undefined) props.reasoning_tokens = usage.reasoningTokens;\n if (usage.cachedInputTokens !== undefined) props.cached_input_tokens = usage.cachedInputTokens;\n }\n\n if (attrs.parameters) {\n if (attrs.parameters.temperature !== undefined) props.$ai_temperature = attrs.parameters.temperature;\n if (attrs.parameters.maxOutputTokens !== undefined) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;\n }\n if (attrs.streaming !== undefined) props.$ai_stream = attrs.streaming;\n\n return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };\n }\n\n private buildSpanProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n\n if (span.input) props.$ai_input_state = span.input;\n if (span.output) props.$ai_output_state = span.output;\n\n if (span.type === SpanType.MODEL_CHUNK) {\n const attrs = span.attributes as any;\n if (attrs?.chunkType) props.chunk_type = attrs.chunkType;\n if (attrs?.sequenceNumber !== undefined) props.chunk_sequence_number = attrs.sequenceNumber;\n }\n\n if (span.attributes) {\n Object.assign(props, span.attributes);\n }\n\n return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };\n }\n\n private formatMessages(data: SpanData, defaultRole: 'user' | 'assistant' = 'user'): PostHogMessage[] {\n if (this.isMessageArray(data)) {\n return data.map(msg => this.normalizeMessage(msg));\n }\n\n if (typeof data === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text: data }] }];\n }\n\n return [{ role: defaultRole, content: [{ type: 'text', text: this.safeStringify(data) }] }];\n }\n\n private isMessageArray(data: unknown): data is MastraMessage[] {\n if (!Array.isArray(data) || data.length === 0) {\n return false;\n }\n\n return data.every(item => typeof item === 'object' && item !== null && 'role' in item && 'content' in item);\n }\n\n private normalizeMessage(msg: MastraMessage): PostHogMessage {\n if (typeof msg.content === 'string') {\n return {\n role: msg.role as PostHogMessage['role'],\n content: [{ type: 'text', text: msg.content }],\n };\n }\n\n return {\n role: msg.role as PostHogMessage['role'],\n content: msg.content as PostHogContent[],\n };\n }\n\n private safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './tracing.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,290 @@
1
+ import { SpanType } from '@mastra/core/observability';
2
+ import { BaseExporter } from '@mastra/observability';
3
+ import { PostHog } from 'posthog-node';
4
+
5
+ // src/tracing.ts
6
+ var PosthogExporter = class _PosthogExporter extends BaseExporter {
7
+ name = "posthog";
8
+ client;
9
+ config;
10
+ traceMap = /* @__PURE__ */ new Map();
11
+ static SERVERLESS_FLUSH_AT = 10;
12
+ static SERVERLESS_FLUSH_INTERVAL = 2e3;
13
+ static DEFAULT_FLUSH_AT = 20;
14
+ static DEFAULT_FLUSH_INTERVAL = 1e4;
15
+ constructor(config) {
16
+ super(config);
17
+ this.config = config;
18
+ if (!config.apiKey) {
19
+ this.setDisabled("Missing required API key");
20
+ this.client = null;
21
+ return;
22
+ }
23
+ const clientConfig = this.buildClientConfig(config);
24
+ this.client = new PostHog(config.apiKey, clientConfig);
25
+ this.logInitialization(config.serverless ?? false, clientConfig);
26
+ }
27
+ buildClientConfig(config) {
28
+ const isServerless = config.serverless ?? false;
29
+ const flushAt = config.flushAt ?? (isServerless ? _PosthogExporter.SERVERLESS_FLUSH_AT : _PosthogExporter.DEFAULT_FLUSH_AT);
30
+ const flushInterval = config.flushInterval ?? (isServerless ? _PosthogExporter.SERVERLESS_FLUSH_INTERVAL : _PosthogExporter.DEFAULT_FLUSH_INTERVAL);
31
+ const host = config.host || process.env.POSTHOG_HOST || "https://us.i.posthog.com";
32
+ if (!config.host && !process.env.POSTHOG_HOST) {
33
+ this.logger.warn(
34
+ 'No PostHog host specified, using US default (https://us.i.posthog.com). For EU region, set `host: "https://eu.i.posthog.com"` in config or POSTHOG_HOST env var. For self-hosted, provide your instance URL.'
35
+ );
36
+ }
37
+ return {
38
+ host,
39
+ flushAt,
40
+ flushInterval,
41
+ privacyMode: config.enablePrivacyMode
42
+ };
43
+ }
44
+ logInitialization(isServerless, config) {
45
+ const message = isServerless ? "PostHog exporter initialized in serverless mode" : "PostHog exporter initialized";
46
+ this.logger.info(message, config);
47
+ }
48
+ async _exportTracingEvent(event) {
49
+ if (!this.client) return;
50
+ try {
51
+ if (event.exportedSpan.isEvent) {
52
+ if (event.type === "span_started") {
53
+ await this.captureEventSpan(event.exportedSpan);
54
+ }
55
+ return;
56
+ }
57
+ switch (event.type) {
58
+ case "span_started":
59
+ await this.handleSpanStarted(event.exportedSpan);
60
+ break;
61
+ case "span_updated":
62
+ break;
63
+ case "span_ended":
64
+ await this.handleSpanEnded(event.exportedSpan);
65
+ break;
66
+ }
67
+ } catch (error) {
68
+ this.logger.error("PostHog exporter error", { error, event });
69
+ }
70
+ }
71
+ async handleSpanStarted(span) {
72
+ let traceData = this.traceMap.get(span.traceId);
73
+ if (!traceData) {
74
+ traceData = {
75
+ spans: /* @__PURE__ */ new Map(),
76
+ distinctId: void 0
77
+ };
78
+ this.traceMap.set(span.traceId, traceData);
79
+ }
80
+ traceData.spans.set(span.id, {
81
+ startTime: this.toDate(span.startTime),
82
+ type: span.type
83
+ });
84
+ if (!traceData.distinctId) {
85
+ const userId = span.metadata?.userId;
86
+ if (userId) {
87
+ traceData.distinctId = String(userId);
88
+ }
89
+ }
90
+ }
91
+ async handleSpanEnded(span) {
92
+ const traceData = this.traceMap.get(span.traceId);
93
+ if (!traceData) {
94
+ this.logger.warn(`Trace data not found for ended span: ${span.id}`);
95
+ return;
96
+ }
97
+ const cachedSpan = traceData.spans.get(span.id);
98
+ if (!cachedSpan) {
99
+ this.logger.warn(`Span cache not found for ended span: ${span.id}`);
100
+ return;
101
+ }
102
+ const startTime = cachedSpan.startTime.getTime();
103
+ const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();
104
+ const latency = (endTime - startTime) / 1e3;
105
+ const eventName = this.mapToPostHogEvent(span.type);
106
+ const distinctId = this.getDistinctId(span, traceData);
107
+ const properties = this.buildEventProperties(span, latency);
108
+ this.client.capture({
109
+ distinctId,
110
+ event: eventName,
111
+ properties,
112
+ timestamp: new Date(endTime)
113
+ });
114
+ traceData.spans.delete(span.id);
115
+ if (traceData.spans.size === 0) {
116
+ this.traceMap.delete(span.traceId);
117
+ }
118
+ }
119
+ async captureEventSpan(span) {
120
+ const eventName = this.mapToPostHogEvent(span.type);
121
+ const traceData = this.traceMap.get(span.traceId);
122
+ const distinctId = this.getDistinctId(span, traceData);
123
+ const properties = this.buildEventProperties(span, 0);
124
+ this.client.capture({
125
+ distinctId,
126
+ event: eventName,
127
+ properties,
128
+ timestamp: span.endTime ? new Date(span.endTime) : /* @__PURE__ */ new Date()
129
+ });
130
+ }
131
+ async shutdown() {
132
+ if (this.client) {
133
+ await this.client.shutdown();
134
+ }
135
+ this.traceMap.clear();
136
+ await super.shutdown();
137
+ this.logger.info("PostHog exporter shutdown complete");
138
+ }
139
+ toDate(timestamp) {
140
+ return timestamp instanceof Date ? timestamp : new Date(timestamp);
141
+ }
142
+ mapToPostHogEvent(spanType) {
143
+ switch (spanType) {
144
+ case SpanType.MODEL_GENERATION:
145
+ case SpanType.MODEL_STEP:
146
+ return "$ai_generation";
147
+ case SpanType.MODEL_CHUNK:
148
+ case SpanType.TOOL_CALL:
149
+ case SpanType.MCP_TOOL_CALL:
150
+ case SpanType.PROCESSOR_RUN:
151
+ case SpanType.AGENT_RUN:
152
+ case SpanType.WORKFLOW_RUN:
153
+ case SpanType.GENERIC:
154
+ default:
155
+ return "$ai_span";
156
+ }
157
+ }
158
+ getDistinctId(span, traceData) {
159
+ if (span.metadata?.userId) {
160
+ return String(span.metadata.userId);
161
+ }
162
+ if (traceData?.distinctId) {
163
+ return traceData.distinctId;
164
+ }
165
+ if (this.config.defaultDistinctId) {
166
+ return this.config.defaultDistinctId;
167
+ }
168
+ return "anonymous";
169
+ }
170
+ buildEventProperties(span, latency) {
171
+ const baseProperties = {
172
+ $ai_trace_id: span.traceId,
173
+ $ai_latency: latency,
174
+ $ai_is_error: !!span.errorInfo
175
+ };
176
+ if (span.parentSpanId) {
177
+ baseProperties.$ai_parent_id = span.parentSpanId;
178
+ }
179
+ if (span.metadata?.sessionId) {
180
+ baseProperties.$ai_session_id = span.metadata.sessionId;
181
+ }
182
+ if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {
183
+ baseProperties.$ai_generation_id = span.id;
184
+ return { ...baseProperties, ...this.buildGenerationProperties(span) };
185
+ } else {
186
+ baseProperties.$ai_span_id = span.id;
187
+ baseProperties.$ai_span_name = span.name;
188
+ return { ...baseProperties, ...this.buildSpanProperties(span) };
189
+ }
190
+ }
191
+ extractErrorProperties(span) {
192
+ if (!span.errorInfo) {
193
+ return {};
194
+ }
195
+ const props = {
196
+ error_message: span.errorInfo.message
197
+ };
198
+ if (span.errorInfo.id) {
199
+ props.error_id = span.errorInfo.id;
200
+ }
201
+ if (span.errorInfo.category) {
202
+ props.error_category = span.errorInfo.category;
203
+ }
204
+ return props;
205
+ }
206
+ extractCustomMetadata(span) {
207
+ const { userId, sessionId, ...customMetadata } = span.metadata ?? {};
208
+ return customMetadata;
209
+ }
210
+ buildGenerationProperties(span) {
211
+ const props = {};
212
+ const attrs = span.attributes ?? {};
213
+ props.$ai_model = attrs.model || "unknown-model";
214
+ props.$ai_provider = attrs.provider || "unknown-provider";
215
+ if (span.input) props.$ai_input = this.formatMessages(span.input, "user");
216
+ if (span.output) props.$ai_output_choices = this.formatMessages(span.output, "assistant");
217
+ if (attrs.usage) {
218
+ const { usage } = attrs;
219
+ const inputTokens = usage.inputTokens ?? usage.promptTokens;
220
+ const outputTokens = usage.outputTokens ?? usage.completionTokens;
221
+ const totalTokens = usage.totalTokens;
222
+ if (inputTokens !== void 0) props.$ai_input_tokens = inputTokens;
223
+ if (outputTokens !== void 0) props.$ai_output_tokens = outputTokens;
224
+ if (totalTokens !== void 0) props.$ai_total_tokens = totalTokens;
225
+ if (usage.reasoningTokens !== void 0) props.reasoning_tokens = usage.reasoningTokens;
226
+ if (usage.cachedInputTokens !== void 0) props.cached_input_tokens = usage.cachedInputTokens;
227
+ }
228
+ if (attrs.parameters) {
229
+ if (attrs.parameters.temperature !== void 0) props.$ai_temperature = attrs.parameters.temperature;
230
+ if (attrs.parameters.maxOutputTokens !== void 0) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;
231
+ }
232
+ if (attrs.streaming !== void 0) props.$ai_stream = attrs.streaming;
233
+ return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };
234
+ }
235
+ buildSpanProperties(span) {
236
+ const props = {};
237
+ if (span.input) props.$ai_input_state = span.input;
238
+ if (span.output) props.$ai_output_state = span.output;
239
+ if (span.type === SpanType.MODEL_CHUNK) {
240
+ const attrs = span.attributes;
241
+ if (attrs?.chunkType) props.chunk_type = attrs.chunkType;
242
+ if (attrs?.sequenceNumber !== void 0) props.chunk_sequence_number = attrs.sequenceNumber;
243
+ }
244
+ if (span.attributes) {
245
+ Object.assign(props, span.attributes);
246
+ }
247
+ return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };
248
+ }
249
+ formatMessages(data, defaultRole = "user") {
250
+ if (this.isMessageArray(data)) {
251
+ return data.map((msg) => this.normalizeMessage(msg));
252
+ }
253
+ if (typeof data === "string") {
254
+ return [{ role: defaultRole, content: [{ type: "text", text: data }] }];
255
+ }
256
+ return [{ role: defaultRole, content: [{ type: "text", text: this.safeStringify(data) }] }];
257
+ }
258
+ isMessageArray(data) {
259
+ if (!Array.isArray(data) || data.length === 0) {
260
+ return false;
261
+ }
262
+ return data.every((item) => typeof item === "object" && item !== null && "role" in item && "content" in item);
263
+ }
264
+ normalizeMessage(msg) {
265
+ if (typeof msg.content === "string") {
266
+ return {
267
+ role: msg.role,
268
+ content: [{ type: "text", text: msg.content }]
269
+ };
270
+ }
271
+ return {
272
+ role: msg.role,
273
+ content: msg.content
274
+ };
275
+ }
276
+ safeStringify(data) {
277
+ try {
278
+ return JSON.stringify(data);
279
+ } catch {
280
+ if (typeof data === "object" && data !== null) {
281
+ return `[Non-serializable ${data.constructor?.name || "Object"}]`;
282
+ }
283
+ return String(data);
284
+ }
285
+ }
286
+ };
287
+
288
+ export { PosthogExporter };
289
+ //# sourceMappingURL=index.js.map
290
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tracing.ts"],"names":[],"mappings":";;;;;AAkDO,IAAM,eAAA,GAAN,MAAM,gBAAA,SAAwB,YAAA,CAAa;AAAA,EAChD,IAAA,GAAO,SAAA;AAAA,EACC,MAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA,uBAAe,GAAA,EAA2B;AAAA,EAElD,OAAwB,mBAAA,GAAsB,EAAA;AAAA,EAC9C,OAAwB,yBAAA,GAA4B,GAAA;AAAA,EACpD,OAAwB,gBAAA,GAAmB,EAAA;AAAA,EAC3C,OAAwB,sBAAA,GAAyB,GAAA;AAAA,EAEjD,YAAY,MAAA,EAA+B;AACzC,IAAA,KAAA,CAAM,MAAM,CAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,IAAA,CAAK,YAAY,0BAA0B,CAAA;AAC3C,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,iBAAA,CAAkB,MAAM,CAAA;AAClD,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,OAAA,CAAQ,MAAA,CAAO,QAAQ,YAAY,CAAA;AACrD,IAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,UAAA,IAAc,KAAA,EAAO,YAAY,CAAA;AAAA,EACjE;AAAA,EAEQ,kBAAkB,MAAA,EAKxB;AACA,IAAA,MAAM,YAAA,GAAe,OAAO,UAAA,IAAc,KAAA;AAC1C,IAAA,MAAM,UACJ,MAAA,CAAO,OAAA,KAAY,YAAA,GAAe,gBAAA,CAAgB,sBAAsB,gBAAA,CAAgB,gBAAA,CAAA;AAC1F,IAAA,MAAM,gBACJ,MAAA,CAAO,aAAA,KACN,YAAA,GAAe,gBAAA,CAAgB,4BAA4B,gBAAA,CAAgB,sBAAA,CAAA;AAE9E,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,IAAQ,OAAA,CAAQ,IAAI,YAAA,IAAgB,0BAAA;AAExD,IAAA,IAAI,CAAC,MAAA,CAAO,IAAA,IAAQ,CAAC,OAAA,CAAQ,IAAI,YAAA,EAAc;AAC7C,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,QACV;AAAA,OAGF;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,OAAA;AAAA,MACA,aAAA;AAAA,MACA,aAAa,MAAA,CAAO;AAAA,KACtB;AAAA,EACF;AAAA,EAEQ,iBAAA,CACN,cACA,MAAA,EACM;AACN,IAAA,MAAM,OAAA,GAAU,eAAe,iDAAA,GAAoD,8BAAA;AAEnF,IAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,MAAM,CAAA;AAAA,EAClC;AAAA,EAEA,MAAgB,oBAAoB,KAAA,EAAoC;AACtE,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAElB,IAAA,IAAI;AACF,MAAA,IAAI,KAAA,CAAM,aAAa,OAAA,EAAS;AAC9B,QAAA,IAAI,KAAA,CAAM,SAAS,cAAA,EAAgB;AACjC,UAAA,MAAM,IAAA,CAAK,gBAAA,CAAiB,KAAA,CAAM,YAAY,CAAA;AAAA,QAChD;AACA,QAAA;AAAA,MACF;AAEA,MAAA,QAAQ,MAAM,IAAA;AAAM,QAClB,KAAK,cAAA;AACH,UAAA,MAAM,IAAA,CAAK,iBAAA,CAAkB,KAAA,CAAM,YAAY,CAAA;AAC/C,UAAA;AAAA,QACF,KAAK,cAAA;AACH,UAAA;AAAA,QACF,KAAK,YAAA;AACH,UAAA,MAAM,IAAA,CAAK,eAAA,CAAgB,KAAA,CAAM,YAAY,CAAA;AAC7C,UAAA;AAAA;AACJ,IACF,SAAS,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,wBAAA,EAA0B,EAAE,KAAA,EAAO,OAAO,CAAA;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,IAAA,EAAsC;AACpE,IAAA,IAAI,SAAA,GAAY,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,OAAO,CAAA;AAE9C,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,GAAY;AAAA,QACV,KAAA,sBAAW,GAAA,EAAI;AAAA,QACf,UAAA,EAAY;AAAA,OACd;AACA,MAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,SAAS,CAAA;AAAA,IAC3C;AAEA,IAAA,SAAA,CAAU,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI;AAAA,MAC3B,SAAA,EAAW,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA;AAAA,MACrC,MAAM,IAAA,CAAK;AAAA,KACZ,CAAA;AAED,IAAA,IAAI,CAAC,UAAU,UAAA,EAAY;AACzB,MAAA,MAAM,MAAA,GAAS,KAAK,QAAA,EAAU,MAAA;AAC9B,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,SAAA,CAAU,UAAA,GAAa,OAAO,MAAM,CAAA;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,IAAA,EAAsC;AAClE,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,OAAO,CAAA;AAEhD,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,qCAAA,EAAwC,IAAA,CAAK,EAAE,CAAA,CAAE,CAAA;AAClE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,SAAA,CAAU,KAAA,CAAM,GAAA,CAAI,KAAK,EAAE,CAAA;AAC9C,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,qCAAA,EAAwC,IAAA,CAAK,EAAE,CAAA,CAAE,CAAA;AAClE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,SAAA,CAAU,OAAA,EAAQ;AAC/C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,GAAU,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAA,CAAK,GAAA,EAAI;AAC9E,IAAA,MAAM,OAAA,GAAA,CAAW,UAAU,SAAA,IAAa,GAAA;AAExC,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA;AAClD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,aAAA,CAAc,IAAA,EAAM,SAAS,CAAA;AACrD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,oBAAA,CAAqB,IAAA,EAAM,OAAO,CAAA;AAE1D,IAAA,IAAA,CAAK,OAAO,OAAA,CAAQ;AAAA,MAClB,UAAA;AAAA,MACA,KAAA,EAAO,SAAA;AAAA,MACP,UAAA;AAAA,MACA,SAAA,EAAW,IAAI,IAAA,CAAK,OAAO;AAAA,KAC5B,CAAA;AAED,IAAA,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA;AAC9B,IAAA,IAAI,SAAA,CAAU,KAAA,CAAM,IAAA,KAAS,CAAA,EAAG;AAC9B,MAAA,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,IAAA,EAAsC;AACnE,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA;AAClD,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,OAAO,CAAA;AAEhD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,aAAA,CAAc,IAAA,EAAM,SAAS,CAAA;AACrD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,oBAAA,CAAqB,IAAA,EAAM,CAAC,CAAA;AAEpD,IAAA,IAAA,CAAK,OAAO,OAAA,CAAQ;AAAA,MAClB,UAAA;AAAA,MACA,KAAA,EAAO,SAAA;AAAA,MACP,UAAA;AAAA,MACA,SAAA,EAAW,KAAK,OAAA,GAAU,IAAI,KAAK,IAAA,CAAK,OAAO,CAAA,mBAAI,IAAI,IAAA;AAAK,KAC7D,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,QAAA,GAA0B;AAC9B,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA,MAAM,IAAA,CAAK,OAAO,QAAA,EAAS;AAAA,IAC7B;AACA,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,IAAA,MAAM,MAAM,QAAA,EAAS;AACrB,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,oCAAoC,CAAA;AAAA,EACvD;AAAA,EAEQ,OAAO,SAAA,EAAgC;AAC7C,IAAA,OAAO,SAAA,YAAqB,IAAA,GAAO,SAAA,GAAY,IAAI,KAAK,SAAS,CAAA;AAAA,EACnE;AAAA,EAEQ,kBAAkB,QAAA,EAA4B;AACpD,IAAA,QAAQ,QAAA;AAAU,MAChB,KAAK,QAAA,CAAS,gBAAA;AAAA,MACd,KAAK,QAAA,CAAS,UAAA;AACZ,QAAA,OAAO,gBAAA;AAAA,MACT,KAAK,QAAA,CAAS,WAAA;AAAA,MACd,KAAK,QAAA,CAAS,SAAA;AAAA,MACd,KAAK,QAAA,CAAS,aAAA;AAAA,MACd,KAAK,QAAA,CAAS,aAAA;AAAA,MACd,KAAK,QAAA,CAAS,SAAA;AAAA,MACd,KAAK,QAAA,CAAS,YAAA;AAAA,MACd,KAAK,QAAA,CAAS,OAAA;AAAA,MACd;AACE,QAAA,OAAO,UAAA;AAAA;AACX,EACF;AAAA,EAEQ,aAAA,CAAc,MAAuB,SAAA,EAAmC;AAC9E,IAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAQ;AACzB,MAAA,OAAO,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA;AAAA,IACpC;AAEA,IAAA,IAAI,WAAW,UAAA,EAAY;AACzB,MAAA,OAAO,SAAA,CAAU,UAAA;AAAA,IACnB;AAEA,IAAA,IAAI,IAAA,CAAK,OAAO,iBAAA,EAAmB;AACjC,MAAA,OAAO,KAAK,MAAA,CAAO,iBAAA;AAAA,IACrB;AAEA,IAAA,OAAO,WAAA;AAAA,EACT;AAAA,EAEQ,oBAAA,CAAqB,MAAuB,OAAA,EAAsC;AACxF,IAAA,MAAM,cAAA,GAAsC;AAAA,MAC1C,cAAc,IAAA,CAAK,OAAA;AAAA,MACnB,WAAA,EAAa,OAAA;AAAA,MACb,YAAA,EAAc,CAAC,CAAC,IAAA,CAAK;AAAA,KACvB;AAEA,IAAA,IAAI,KAAK,YAAA,EAAc;AACrB,MAAA,cAAA,CAAe,gBAAgB,IAAA,CAAK,YAAA;AAAA,IACtC;AAEA,IAAA,IAAI,IAAA,CAAK,UAAU,SAAA,EAAW;AAC5B,MAAA,cAAA,CAAe,cAAA,GAAiB,KAAK,QAAA,CAAS,SAAA;AAAA,IAChD;AAEA,IAAA,IAAI,KAAK,IAAA,KAAS,QAAA,CAAS,oBAAoB,IAAA,CAAK,IAAA,KAAS,SAAS,UAAA,EAAY;AAChF,MAAA,cAAA,CAAe,oBAAoB,IAAA,CAAK,EAAA;AACxC,MAAA,OAAO,EAAE,GAAG,cAAA,EAAgB,GAAG,IAAA,CAAK,yBAAA,CAA0B,IAAI,CAAA,EAAE;AAAA,IACtE,CAAA,MAAO;AACL,MAAA,cAAA,CAAe,cAAc,IAAA,CAAK,EAAA;AAClC,MAAA,cAAA,CAAe,gBAAgB,IAAA,CAAK,IAAA;AACpC,MAAA,OAAO,EAAE,GAAG,cAAA,EAAgB,GAAG,IAAA,CAAK,mBAAA,CAAoB,IAAI,CAAA,EAAE;AAAA,IAChE;AAAA,EACF;AAAA,EAEQ,uBAAuB,IAAA,EAA4C;AACzE,IAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,MAAM,KAAA,GAAgC;AAAA,MACpC,aAAA,EAAe,KAAK,SAAA,CAAU;AAAA,KAChC;AAEA,IAAA,IAAI,IAAA,CAAK,UAAU,EAAA,EAAI;AACrB,MAAA,KAAA,CAAM,QAAA,GAAW,KAAK,SAAA,CAAU,EAAA;AAAA,IAClC;AAEA,IAAA,IAAI,IAAA,CAAK,UAAU,QAAA,EAAU;AAC3B,MAAA,KAAA,CAAM,cAAA,GAAiB,KAAK,SAAA,CAAU,QAAA;AAAA,IACxC;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEQ,sBAAsB,IAAA,EAA4C;AACxE,IAAA,MAAM,EAAE,QAAQ,SAAA,EAAW,GAAG,gBAAe,GAAI,IAAA,CAAK,YAAY,EAAC;AACnE,IAAA,OAAO,cAAA;AAAA,EACT;AAAA,EAEQ,0BAA0B,IAAA,EAA4C;AAC5E,IAAA,MAAM,QAA6B,EAAC;AACpC,IAAA,MAAM,KAAA,GAAS,IAAA,CAAK,UAAA,IAAc,EAAC;AAEnC,IAAA,KAAA,CAAM,SAAA,GAAY,MAAM,KAAA,IAAS,eAAA;AACjC,IAAA,KAAA,CAAM,YAAA,GAAe,MAAM,QAAA,IAAY,kBAAA;AAEvC,IAAA,IAAI,IAAA,CAAK,OAAO,KAAA,CAAM,SAAA,GAAY,KAAK,cAAA,CAAe,IAAA,CAAK,OAAO,MAAM,CAAA;AACxE,IAAA,IAAI,IAAA,CAAK,QAAQ,KAAA,CAAM,kBAAA,GAAqB,KAAK,cAAA,CAAe,IAAA,CAAK,QAAQ,WAAW,CAAA;AAExF,IAAA,IAAI,MAAM,KAAA,EAAO;AACf,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,WAAA,GAAc,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,YAAA;AAC/C,MAAA,MAAM,YAAA,GAAe,KAAA,CAAM,YAAA,IAAgB,KAAA,CAAM,gBAAA;AACjD,MAAA,MAAM,cAAc,KAAA,CAAM,WAAA;AAE1B,MAAA,IAAI,WAAA,KAAgB,MAAA,EAAW,KAAA,CAAM,gBAAA,GAAmB,WAAA;AACxD,MAAA,IAAI,YAAA,KAAiB,MAAA,EAAW,KAAA,CAAM,iBAAA,GAAoB,YAAA;AAC1D,MAAA,IAAI,WAAA,KAAgB,MAAA,EAAW,KAAA,CAAM,gBAAA,GAAmB,WAAA;AAExD,MAAA,IAAI,KAAA,CAAM,eAAA,KAAoB,MAAA,EAAW,KAAA,CAAM,mBAAmB,KAAA,CAAM,eAAA;AACxE,MAAA,IAAI,KAAA,CAAM,iBAAA,KAAsB,MAAA,EAAW,KAAA,CAAM,sBAAsB,KAAA,CAAM,iBAAA;AAAA,IAC/E;AAEA,IAAA,IAAI,MAAM,UAAA,EAAY;AACpB,MAAA,IAAI,MAAM,UAAA,CAAW,WAAA,KAAgB,QAAW,KAAA,CAAM,eAAA,GAAkB,MAAM,UAAA,CAAW,WAAA;AACzF,MAAA,IAAI,MAAM,UAAA,CAAW,eAAA,KAAoB,QAAW,KAAA,CAAM,cAAA,GAAiB,MAAM,UAAA,CAAW,eAAA;AAAA,IAC9F;AACA,IAAA,IAAI,KAAA,CAAM,SAAA,KAAc,MAAA,EAAW,KAAA,CAAM,aAAa,KAAA,CAAM,SAAA;AAE5D,IAAA,OAAO,EAAE,GAAG,KAAA,EAAO,GAAG,IAAA,CAAK,sBAAA,CAAuB,IAAI,CAAA,EAAG,GAAG,IAAA,CAAK,qBAAA,CAAsB,IAAI,CAAA,EAAE;AAAA,EAC/F;AAAA,EAEQ,oBAAoB,IAAA,EAA4C;AACtE,IAAA,MAAM,QAA6B,EAAC;AAEpC,IAAA,IAAI,IAAA,CAAK,KAAA,EAAO,KAAA,CAAM,eAAA,GAAkB,IAAA,CAAK,KAAA;AAC7C,IAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,KAAA,CAAM,gBAAA,GAAmB,IAAA,CAAK,MAAA;AAE/C,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,QAAA,CAAS,WAAA,EAAa;AACtC,MAAA,MAAM,QAAQ,IAAA,CAAK,UAAA;AACnB,MAAA,IAAI,KAAA,EAAO,SAAA,EAAW,KAAA,CAAM,UAAA,GAAa,KAAA,CAAM,SAAA;AAC/C,MAAA,IAAI,KAAA,EAAO,cAAA,KAAmB,MAAA,EAAW,KAAA,CAAM,wBAAwB,KAAA,CAAM,cAAA;AAAA,IAC/E;AAEA,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,IAAA,CAAK,UAAU,CAAA;AAAA,IACtC;AAEA,IAAA,OAAO,EAAE,GAAG,KAAA,EAAO,GAAG,IAAA,CAAK,sBAAA,CAAuB,IAAI,CAAA,EAAG,GAAG,IAAA,CAAK,qBAAA,CAAsB,IAAI,CAAA,EAAE;AAAA,EAC/F;AAAA,EAEQ,cAAA,CAAe,IAAA,EAAgB,WAAA,GAAoC,MAAA,EAA0B;AACnG,IAAA,IAAI,IAAA,CAAK,cAAA,CAAe,IAAI,CAAA,EAAG;AAC7B,MAAA,OAAO,KAAK,GAAA,CAAI,CAAA,GAAA,KAAO,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAC,CAAA;AAAA,IACnD;AAEA,IAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,MAAA,OAAO,CAAC,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,GAAG,CAAA;AAAA,IACxE;AAEA,IAAA,OAAO,CAAC,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,KAAK,aAAA,CAAc,IAAI,CAAA,EAAG,GAAG,CAAA;AAAA,EAC5F;AAAA,EAEQ,eAAe,IAAA,EAAwC;AAC7D,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC7C,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,IAAA,KAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,IAAQ,MAAA,IAAU,IAAA,IAAQ,SAAA,IAAa,IAAI,CAAA;AAAA,EAC5G;AAAA,EAEQ,iBAAiB,GAAA,EAAoC;AAC3D,IAAA,IAAI,OAAO,GAAA,CAAI,OAAA,KAAY,QAAA,EAAU;AACnC,MAAA,OAAO;AAAA,QACL,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,QAAQ,IAAA,EAAM,GAAA,CAAI,SAAS;AAAA,OAC/C;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,SAAS,GAAA,CAAI;AAAA,KACf;AAAA,EACF;AAAA,EAEQ,cAAc,IAAA,EAAuB;AAC3C,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,IAC5B,CAAA,CAAA,MAAQ;AACN,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,EAAM;AAC7C,QAAA,OAAO,CAAA,kBAAA,EAAqB,IAAA,CAAK,WAAA,EAAa,IAAA,IAAQ,QAAQ,CAAA,CAAA,CAAA;AAAA,MAChE;AACA,MAAA,OAAO,OAAO,IAAI,CAAA;AAAA,IACpB;AAAA,EACF;AACF","file":"index.js","sourcesContent":["import type { TracingEvent, AnyExportedSpan, ModelGenerationAttributes } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport { BaseExporter } from '@mastra/observability';\nimport { PostHog } from 'posthog-node';\n\ninterface PostHogMessage {\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: PostHogContent[];\n}\n\ninterface PostHogContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ninterface MastraMessage {\n role: string;\n content: string | MastraContent[];\n}\n\ninterface MastraContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ntype SpanData = string | MastraMessage[] | Record<string, unknown> | unknown;\n\nexport interface PosthogExporterConfig extends BaseExporterConfig {\n apiKey: string;\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n serverless?: boolean;\n defaultDistinctId?: string;\n enablePrivacyMode?: boolean;\n}\n\ntype SpanCache = {\n startTime: Date;\n type: SpanType;\n};\n\ntype TraceMetadata = {\n spans: Map<string, SpanCache>;\n distinctId?: string;\n};\n\nexport class PosthogExporter extends BaseExporter {\n name = 'posthog';\n private client: PostHog;\n private config: PosthogExporterConfig;\n private traceMap = new Map<string, TraceMetadata>();\n\n private static readonly SERVERLESS_FLUSH_AT = 10;\n private static readonly SERVERLESS_FLUSH_INTERVAL = 2000;\n private static readonly DEFAULT_FLUSH_AT = 20;\n private static readonly DEFAULT_FLUSH_INTERVAL = 10000;\n\n constructor(config: PosthogExporterConfig) {\n super(config);\n this.config = config;\n\n if (!config.apiKey) {\n this.setDisabled('Missing required API key');\n this.client = null as any;\n return;\n }\n\n const clientConfig = this.buildClientConfig(config);\n this.client = new PostHog(config.apiKey, clientConfig);\n this.logInitialization(config.serverless ?? false, clientConfig);\n }\n\n private buildClientConfig(config: PosthogExporterConfig): {\n host: string;\n flushAt: number;\n flushInterval: number;\n privacyMode?: boolean;\n } {\n const isServerless = config.serverless ?? false;\n const flushAt =\n config.flushAt ?? (isServerless ? PosthogExporter.SERVERLESS_FLUSH_AT : PosthogExporter.DEFAULT_FLUSH_AT);\n const flushInterval =\n config.flushInterval ??\n (isServerless ? PosthogExporter.SERVERLESS_FLUSH_INTERVAL : PosthogExporter.DEFAULT_FLUSH_INTERVAL);\n\n const host = config.host || process.env.POSTHOG_HOST || 'https://us.i.posthog.com';\n\n if (!config.host && !process.env.POSTHOG_HOST) {\n this.logger.warn(\n 'No PostHog host specified, using US default (https://us.i.posthog.com). ' +\n 'For EU region, set `host: \"https://eu.i.posthog.com\"` in config or POSTHOG_HOST env var. ' +\n 'For self-hosted, provide your instance URL.',\n );\n }\n\n return {\n host,\n flushAt,\n flushInterval,\n privacyMode: config.enablePrivacyMode,\n };\n }\n\n private logInitialization(\n isServerless: boolean,\n config: { host: string; flushAt: number; flushInterval: number },\n ): void {\n const message = isServerless ? 'PostHog exporter initialized in serverless mode' : 'PostHog exporter initialized';\n\n this.logger.info(message, config);\n }\n\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (!this.client) return;\n\n try {\n if (event.exportedSpan.isEvent) {\n if (event.type === 'span_started') {\n await this.captureEventSpan(event.exportedSpan);\n }\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.exportedSpan);\n break;\n case 'span_updated':\n break;\n case 'span_ended':\n await this.handleSpanEnded(event.exportedSpan);\n break;\n }\n } catch (error) {\n this.logger.error('PostHog exporter error', { error, event });\n }\n }\n\n private async handleSpanStarted(span: AnyExportedSpan): Promise<void> {\n let traceData = this.traceMap.get(span.traceId);\n\n if (!traceData) {\n traceData = {\n spans: new Map(),\n distinctId: undefined,\n };\n this.traceMap.set(span.traceId, traceData);\n }\n\n traceData.spans.set(span.id, {\n startTime: this.toDate(span.startTime),\n type: span.type,\n });\n\n if (!traceData.distinctId) {\n const userId = span.metadata?.userId;\n if (userId) {\n traceData.distinctId = String(userId);\n }\n }\n }\n\n private async handleSpanEnded(span: AnyExportedSpan): Promise<void> {\n const traceData = this.traceMap.get(span.traceId);\n\n if (!traceData) {\n this.logger.warn(`Trace data not found for ended span: ${span.id}`);\n return;\n }\n\n const cachedSpan = traceData.spans.get(span.id);\n if (!cachedSpan) {\n this.logger.warn(`Span cache not found for ended span: ${span.id}`);\n return;\n }\n\n const startTime = cachedSpan.startTime.getTime();\n const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();\n const latency = (endTime - startTime) / 1000;\n\n const eventName = this.mapToPostHogEvent(span.type);\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, latency);\n\n this.client.capture({\n distinctId,\n event: eventName,\n properties,\n timestamp: new Date(endTime),\n });\n\n traceData.spans.delete(span.id);\n if (traceData.spans.size === 0) {\n this.traceMap.delete(span.traceId);\n }\n }\n\n private async captureEventSpan(span: AnyExportedSpan): Promise<void> {\n const eventName = this.mapToPostHogEvent(span.type);\n const traceData = this.traceMap.get(span.traceId);\n\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, 0);\n\n this.client.capture({\n distinctId,\n event: eventName,\n properties,\n timestamp: span.endTime ? new Date(span.endTime) : new Date(),\n });\n }\n\n async shutdown(): Promise<void> {\n if (this.client) {\n await this.client.shutdown();\n }\n this.traceMap.clear();\n await super.shutdown();\n this.logger.info('PostHog exporter shutdown complete');\n }\n\n private toDate(timestamp: Date | number): Date {\n return timestamp instanceof Date ? timestamp : new Date(timestamp);\n }\n\n private mapToPostHogEvent(spanType: SpanType): string {\n switch (spanType) {\n case SpanType.MODEL_GENERATION:\n case SpanType.MODEL_STEP:\n return '$ai_generation';\n case SpanType.MODEL_CHUNK:\n case SpanType.TOOL_CALL:\n case SpanType.MCP_TOOL_CALL:\n case SpanType.PROCESSOR_RUN:\n case SpanType.AGENT_RUN:\n case SpanType.WORKFLOW_RUN:\n case SpanType.GENERIC:\n default:\n return '$ai_span';\n }\n }\n\n private getDistinctId(span: AnyExportedSpan, traceData?: TraceMetadata): string {\n if (span.metadata?.userId) {\n return String(span.metadata.userId);\n }\n\n if (traceData?.distinctId) {\n return traceData.distinctId;\n }\n\n if (this.config.defaultDistinctId) {\n return this.config.defaultDistinctId;\n }\n\n return 'anonymous';\n }\n\n private buildEventProperties(span: AnyExportedSpan, latency: number): Record<string, any> {\n const baseProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_latency: latency,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.parentSpanId) {\n baseProperties.$ai_parent_id = span.parentSpanId;\n }\n\n if (span.metadata?.sessionId) {\n baseProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {\n baseProperties.$ai_generation_id = span.id;\n return { ...baseProperties, ...this.buildGenerationProperties(span) };\n } else {\n baseProperties.$ai_span_id = span.id;\n baseProperties.$ai_span_name = span.name;\n return { ...baseProperties, ...this.buildSpanProperties(span) };\n }\n }\n\n private extractErrorProperties(span: AnyExportedSpan): Record<string, any> {\n if (!span.errorInfo) {\n return {};\n }\n\n const props: Record<string, string> = {\n error_message: span.errorInfo.message,\n };\n\n if (span.errorInfo.id) {\n props.error_id = span.errorInfo.id;\n }\n\n if (span.errorInfo.category) {\n props.error_category = span.errorInfo.category;\n }\n\n return props;\n }\n\n private extractCustomMetadata(span: AnyExportedSpan): Record<string, any> {\n const { userId, sessionId, ...customMetadata } = span.metadata ?? {};\n return customMetadata;\n }\n\n private buildGenerationProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n const attrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n props.$ai_model = attrs.model || 'unknown-model';\n props.$ai_provider = attrs.provider || 'unknown-provider';\n\n if (span.input) props.$ai_input = this.formatMessages(span.input, 'user');\n if (span.output) props.$ai_output_choices = this.formatMessages(span.output, 'assistant');\n\n if (attrs.usage) {\n const { usage } = attrs;\n const inputTokens = usage.inputTokens ?? usage.promptTokens;\n const outputTokens = usage.outputTokens ?? usage.completionTokens;\n const totalTokens = usage.totalTokens;\n\n if (inputTokens !== undefined) props.$ai_input_tokens = inputTokens;\n if (outputTokens !== undefined) props.$ai_output_tokens = outputTokens;\n if (totalTokens !== undefined) props.$ai_total_tokens = totalTokens;\n\n if (usage.reasoningTokens !== undefined) props.reasoning_tokens = usage.reasoningTokens;\n if (usage.cachedInputTokens !== undefined) props.cached_input_tokens = usage.cachedInputTokens;\n }\n\n if (attrs.parameters) {\n if (attrs.parameters.temperature !== undefined) props.$ai_temperature = attrs.parameters.temperature;\n if (attrs.parameters.maxOutputTokens !== undefined) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;\n }\n if (attrs.streaming !== undefined) props.$ai_stream = attrs.streaming;\n\n return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };\n }\n\n private buildSpanProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n\n if (span.input) props.$ai_input_state = span.input;\n if (span.output) props.$ai_output_state = span.output;\n\n if (span.type === SpanType.MODEL_CHUNK) {\n const attrs = span.attributes as any;\n if (attrs?.chunkType) props.chunk_type = attrs.chunkType;\n if (attrs?.sequenceNumber !== undefined) props.chunk_sequence_number = attrs.sequenceNumber;\n }\n\n if (span.attributes) {\n Object.assign(props, span.attributes);\n }\n\n return { ...props, ...this.extractErrorProperties(span), ...this.extractCustomMetadata(span) };\n }\n\n private formatMessages(data: SpanData, defaultRole: 'user' | 'assistant' = 'user'): PostHogMessage[] {\n if (this.isMessageArray(data)) {\n return data.map(msg => this.normalizeMessage(msg));\n }\n\n if (typeof data === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text: data }] }];\n }\n\n return [{ role: defaultRole, content: [{ type: 'text', text: this.safeStringify(data) }] }];\n }\n\n private isMessageArray(data: unknown): data is MastraMessage[] {\n if (!Array.isArray(data) || data.length === 0) {\n return false;\n }\n\n return data.every(item => typeof item === 'object' && item !== null && 'role' in item && 'content' in item);\n }\n\n private normalizeMessage(msg: MastraMessage): PostHogMessage {\n if (typeof msg.content === 'string') {\n return {\n role: msg.role as PostHogMessage['role'],\n content: [{ type: 'text', text: msg.content }],\n };\n }\n\n return {\n role: msg.role as PostHogMessage['role'],\n content: msg.content as PostHogContent[],\n };\n }\n\n private safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import type { TracingEvent } from '@mastra/core/observability';
2
+ import type { BaseExporterConfig } from '@mastra/observability';
3
+ import { BaseExporter } from '@mastra/observability';
4
+ export interface PosthogExporterConfig extends BaseExporterConfig {
5
+ apiKey: string;
6
+ host?: string;
7
+ flushAt?: number;
8
+ flushInterval?: number;
9
+ serverless?: boolean;
10
+ defaultDistinctId?: string;
11
+ enablePrivacyMode?: boolean;
12
+ }
13
+ export declare class PosthogExporter extends BaseExporter {
14
+ name: string;
15
+ private client;
16
+ private config;
17
+ private traceMap;
18
+ private static readonly SERVERLESS_FLUSH_AT;
19
+ private static readonly SERVERLESS_FLUSH_INTERVAL;
20
+ private static readonly DEFAULT_FLUSH_AT;
21
+ private static readonly DEFAULT_FLUSH_INTERVAL;
22
+ constructor(config: PosthogExporterConfig);
23
+ private buildClientConfig;
24
+ private logInitialization;
25
+ protected _exportTracingEvent(event: TracingEvent): Promise<void>;
26
+ private handleSpanStarted;
27
+ private handleSpanEnded;
28
+ private captureEventSpan;
29
+ shutdown(): Promise<void>;
30
+ private toDate;
31
+ private mapToPostHogEvent;
32
+ private getDistinctId;
33
+ private buildEventProperties;
34
+ private extractErrorProperties;
35
+ private extractCustomMetadata;
36
+ private buildGenerationProperties;
37
+ private buildSpanProperties;
38
+ private formatMessages;
39
+ private isMessageArray;
40
+ private normalizeMessage;
41
+ private safeStringify;
42
+ }
43
+ //# sourceMappingURL=tracing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA8C,MAAM,4BAA4B,CAAC;AAE3G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AA2BrD,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAYD,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,IAAI,SAAa;IACjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,QAAQ,CAAoC;IAEpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAM;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAQ;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAM;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAS;gBAE3C,MAAM,EAAE,qBAAqB;IAezC,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,iBAAiB;cAST,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YA0BzD,iBAAiB;YAwBjB,eAAe;YAmCf,gBAAgB;IAexB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAS/B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,sBAAsB;IAoB9B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,yBAAyB;IAiCjC,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,aAAa;CAUtB"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@mastra/posthog",
3
+ "version": "0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939",
4
+ "description": "PostHog observability provider for Mastra",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "CHANGELOG.md"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "require": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.cjs"
21
+ }
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "posthog-node": "^4.0.1",
28
+ "@mastra/observability": "0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939"
29
+ },
30
+ "devDependencies": {
31
+ "@microsoft/api-extractor": "^7.52.8",
32
+ "@types/node": "^20.19.0",
33
+ "eslint": "^9.37.0",
34
+ "tsup": "^8.5.0",
35
+ "typescript": "^5.8.3",
36
+ "vitest": "^3.2.4",
37
+ "@mastra/core": "0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939",
38
+ "@internal/types-builder": "0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939",
39
+ "@internal/lint": "0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939"
40
+ },
41
+ "peerDependencies": {
42
+ "@mastra/core": "0.0.0-fix-issue-10434-concurrent-write-corruption-20251124213939"
43
+ },
44
+ "homepage": "https://mastra.ai",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/mastra-ai/mastra.git",
48
+ "directory": "observability/posthog"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/mastra-ai/mastra/issues"
52
+ },
53
+ "engines": {
54
+ "node": ">=22.13.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsup --silent --config tsup.config.ts",
58
+ "build:watch": "pnpm build --watch",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest watch",
61
+ "lint": "eslint ."
62
+ }
63
+ }