@redthreadlabs/tracelog 1.4.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.
Files changed (127) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +126 -0
  3. package/index.d.ts +464 -0
  4. package/index.js +11 -0
  5. package/lib/InflightEventSet.js +53 -0
  6. package/lib/activation-method.js +97 -0
  7. package/lib/agent.js +1226 -0
  8. package/lib/apm-client/apm-client.js +107 -0
  9. package/lib/apm-client/channel-writer.js +334 -0
  10. package/lib/apm-client/jsonl-file-client.js +241 -0
  11. package/lib/apm-client/ndjson.js +20 -0
  12. package/lib/apm-client/noop-apm-client.js +79 -0
  13. package/lib/apm-client/s3-uploader.js +308 -0
  14. package/lib/apm-client/truncate.js +507 -0
  15. package/lib/async-hooks-polyfill.js +58 -0
  16. package/lib/cloud-metadata/aws.js +175 -0
  17. package/lib/cloud-metadata/azure.js +123 -0
  18. package/lib/cloud-metadata/callback-coordination.js +159 -0
  19. package/lib/cloud-metadata/gcp.js +133 -0
  20. package/lib/cloud-metadata/index.js +175 -0
  21. package/lib/config/config.js +431 -0
  22. package/lib/config/normalizers.js +649 -0
  23. package/lib/config/schema.js +946 -0
  24. package/lib/constants.js +35 -0
  25. package/lib/errors.js +303 -0
  26. package/lib/filters/sanitize-field-names.js +69 -0
  27. package/lib/http-request.js +249 -0
  28. package/lib/instrumentation/context.js +56 -0
  29. package/lib/instrumentation/dropped-spans-stats.js +112 -0
  30. package/lib/instrumentation/elasticsearch-shared.js +63 -0
  31. package/lib/instrumentation/express-utils.js +91 -0
  32. package/lib/instrumentation/generic-span.js +322 -0
  33. package/lib/instrumentation/http-shared.js +424 -0
  34. package/lib/instrumentation/ids.js +39 -0
  35. package/lib/instrumentation/index.js +1078 -0
  36. package/lib/instrumentation/modules/@apollo/server.js +39 -0
  37. package/lib/instrumentation/modules/@aws-sdk/client-dynamodb.js +143 -0
  38. package/lib/instrumentation/modules/@aws-sdk/client-s3.js +230 -0
  39. package/lib/instrumentation/modules/@aws-sdk/client-sns.js +197 -0
  40. package/lib/instrumentation/modules/@aws-sdk/client-sqs.js +336 -0
  41. package/lib/instrumentation/modules/@elastic/elasticsearch.js +343 -0
  42. package/lib/instrumentation/modules/@hapi/hapi.js +221 -0
  43. package/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js +178 -0
  44. package/lib/instrumentation/modules/@redis/client/dist/lib/client/index.js +49 -0
  45. package/lib/instrumentation/modules/@smithy/smithy-client.js +198 -0
  46. package/lib/instrumentation/modules/apollo-server-core.js +49 -0
  47. package/lib/instrumentation/modules/aws-sdk/dynamodb.js +155 -0
  48. package/lib/instrumentation/modules/aws-sdk/s3.js +184 -0
  49. package/lib/instrumentation/modules/aws-sdk/sns.js +232 -0
  50. package/lib/instrumentation/modules/aws-sdk/sqs.js +361 -0
  51. package/lib/instrumentation/modules/aws-sdk.js +76 -0
  52. package/lib/instrumentation/modules/bluebird.js +93 -0
  53. package/lib/instrumentation/modules/cassandra-driver.js +280 -0
  54. package/lib/instrumentation/modules/elasticsearch.js +200 -0
  55. package/lib/instrumentation/modules/express-graphql.js +66 -0
  56. package/lib/instrumentation/modules/express-queue.js +28 -0
  57. package/lib/instrumentation/modules/express.js +162 -0
  58. package/lib/instrumentation/modules/fastify.js +179 -0
  59. package/lib/instrumentation/modules/finalhandler.js +41 -0
  60. package/lib/instrumentation/modules/generic-pool.js +85 -0
  61. package/lib/instrumentation/modules/graphql.js +256 -0
  62. package/lib/instrumentation/modules/handlebars.js +33 -0
  63. package/lib/instrumentation/modules/http.js +112 -0
  64. package/lib/instrumentation/modules/http2.js +320 -0
  65. package/lib/instrumentation/modules/https.js +68 -0
  66. package/lib/instrumentation/modules/ioredis.js +94 -0
  67. package/lib/instrumentation/modules/jade.js +29 -0
  68. package/lib/instrumentation/modules/kafkajs.js +476 -0
  69. package/lib/instrumentation/modules/knex.js +91 -0
  70. package/lib/instrumentation/modules/koa-router.js +74 -0
  71. package/lib/instrumentation/modules/koa.js +15 -0
  72. package/lib/instrumentation/modules/memcached.js +100 -0
  73. package/lib/instrumentation/modules/mimic-response.js +45 -0
  74. package/lib/instrumentation/modules/mongodb/lib/cmap/connection_pool.js +40 -0
  75. package/lib/instrumentation/modules/mongodb-core.js +206 -0
  76. package/lib/instrumentation/modules/mongodb.js +259 -0
  77. package/lib/instrumentation/modules/mysql.js +200 -0
  78. package/lib/instrumentation/modules/mysql2.js +140 -0
  79. package/lib/instrumentation/modules/pg.js +148 -0
  80. package/lib/instrumentation/modules/pug.js +29 -0
  81. package/lib/instrumentation/modules/redis.js +176 -0
  82. package/lib/instrumentation/modules/restify.js +52 -0
  83. package/lib/instrumentation/modules/tedious.js +159 -0
  84. package/lib/instrumentation/modules/undici.js +270 -0
  85. package/lib/instrumentation/modules/ws.js +59 -0
  86. package/lib/instrumentation/noop-transaction.js +81 -0
  87. package/lib/instrumentation/run-context/AbstractRunContextManager.js +215 -0
  88. package/lib/instrumentation/run-context/AsyncHooksRunContextManager.js +106 -0
  89. package/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js +73 -0
  90. package/lib/instrumentation/run-context/BasicRunContextManager.js +82 -0
  91. package/lib/instrumentation/run-context/RunContext.js +151 -0
  92. package/lib/instrumentation/run-context/index.js +23 -0
  93. package/lib/instrumentation/shimmer.js +123 -0
  94. package/lib/instrumentation/span-compression.js +239 -0
  95. package/lib/instrumentation/span.js +621 -0
  96. package/lib/instrumentation/template-shared.js +43 -0
  97. package/lib/instrumentation/timer.js +84 -0
  98. package/lib/instrumentation/transaction.js +571 -0
  99. package/lib/load-source-map.js +100 -0
  100. package/lib/logging.js +212 -0
  101. package/lib/metrics/index.js +92 -0
  102. package/lib/metrics/platforms/generic/index.js +40 -0
  103. package/lib/metrics/platforms/generic/process-cpu.js +22 -0
  104. package/lib/metrics/platforms/generic/process-top.js +157 -0
  105. package/lib/metrics/platforms/generic/stats.js +34 -0
  106. package/lib/metrics/platforms/generic/system-cpu.js +51 -0
  107. package/lib/metrics/platforms/linux/index.js +19 -0
  108. package/lib/metrics/platforms/linux/stats.js +213 -0
  109. package/lib/metrics/queue.js +90 -0
  110. package/lib/metrics/registry.js +52 -0
  111. package/lib/metrics/reporter.js +119 -0
  112. package/lib/metrics/runtime.js +77 -0
  113. package/lib/middleware/connect.js +16 -0
  114. package/lib/parsers.js +225 -0
  115. package/lib/propwrap.js +147 -0
  116. package/lib/stacktraces.js +537 -0
  117. package/lib/symbols.js +15 -0
  118. package/lib/tracecontext/index.js +115 -0
  119. package/lib/tracecontext/traceparent.js +185 -0
  120. package/lib/tracecontext/tracestate.js +388 -0
  121. package/lib/wildcard-matcher.js +52 -0
  122. package/loader.mjs +7 -0
  123. package/package.json +98 -0
  124. package/start.d.ts +8 -0
  125. package/start.js +29 -0
  126. package/types/aws-lambda.d.ts +98 -0
  127. package/types/connect.d.ts +23 -0
package/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2012, Matt Robenolt
4
+ Copyright (c) 2013-2014, Thomas Watson Steen and Elasticsearch B.V.
5
+ Copyright (c) 2015-2023, Elasticsearch B.V.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ 1. Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # Tracelog
2
+
3
+ Node.js APM instrumentation that writes traces to local JSONL files, with automatic rotation and optional S3 upload.
4
+
5
+ Forked from [elastic-apm-node](https://github.com/elastic/apm-agent-nodejs) v4.15.0. All 43 auto-instrumentation modules are preserved (Express, Fastify, Koa, PostgreSQL, MongoDB, Redis, AWS SDK, etc.), but instead of shipping data to an Elastic APM server, everything is written to timestamped `.jsonl` files on disk with time-based and size-based rotation.
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ npm install tracelog
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Start tracelog at the very top of your application, before importing anything else:
16
+
17
+ ```js
18
+ require('tracelog').start({
19
+ serviceName: 'my-api',
20
+ serviceVersion: '1.0.0',
21
+ logDir: '/var/log/myapp',
22
+ s3Bucket: 'my-traces',
23
+ s3Region: 'us-east-1',
24
+ s3KeyTemplate: '{serviceName}/{environment}/{date}/{hostname}-{pid}-{timestamp}.jsonl',
25
+ });
26
+ ```
27
+
28
+ Or use the auto-start entry point with environment variables:
29
+
30
+ ```bash
31
+ TRACELOG_SERVICE_NAME=my-api \
32
+ node -r tracelog/start app.js
33
+ ```
34
+
35
+ That's it. Tracelog will automatically instrument your HTTP servers, database clients, and other modules, writing transaction, span, error, and metric data to the JSONL file. If `s3Bucket` is set, completed (rotated) files are gzipped and uploaded to S3, then deleted locally.
36
+
37
+ ## Custom events
38
+
39
+ Tracelog adds a custom **event** type that has no equivalent in Elastic APM or OpenTelemetry. Events are free-form records for anything that isn't a trace, error, or metric — user analytics, audit logs, client-side telemetry from mobile or browser apps, or structured log lines.
40
+
41
+ ```js
42
+ // Single event
43
+ apm.captureEvent('page_view', {
44
+ message: 'User viewed dashboard',
45
+ level: 'info',
46
+ user: { id: 'u-abc123', username: 'jane_doe' },
47
+ client: { name: 'duiduidui-ios', version: '2.4.1' },
48
+ params: { page: '/dashboard', referrer: '/home' },
49
+ });
50
+ ```
51
+
52
+ Events support standardized fields for user identity (`user`), client environment (`client`), severity (`level`), timing (`duration`), and an open-ended `params` object for anything else. Only `type` is required.
53
+
54
+ For server endpoints that receive batches of events from client devices, use `captureEvents`:
55
+
56
+ ```js
57
+ // Batch — e.g. from a mobile app uploading queued events
58
+ app.post('/events', (req, res) => {
59
+ apm.captureEvents(req.body.events, () => res.sendStatus(202));
60
+ });
61
+ ```
62
+
63
+ Each event in the batch is individually filtered (via `addEventFilter`) and written as a separate JSONL line. See **[SCHEMA.md](SCHEMA.md)** for the full event schema.
64
+
65
+ ## Output format
66
+
67
+ Each line is a self-contained JSON object with one top-level key identifying the event type. There are six event types: `metadata`, `transaction`, `span`, `error`, `metricset`, and `event`. Files start with a metadata line:
68
+
69
+ ```jsonl
70
+ {"metadata":{"service":{"name":"my-api","version":"1.0.0"},"process":{"pid":1234},"system":{"hostname":"ip-10-0-1-42"},"cloud":{"provider":"aws","instance":{"id":"i-0abc123"},"availability_zone":"us-east-1a"}}}
71
+ {"transaction":{"id":"abc123","trace_id":"def456","name":"GET /users","type":"request","duration":42.5,"result":"HTTP 2xx","sampled":true,"outcome":"success","span_count":{"started":1}}}
72
+ {"span":{"id":"ghi789","transaction_id":"abc123","trace_id":"def456","parent_id":"abc123","name":"SELECT * FROM users","type":"db","subtype":"postgresql","duration":12.3,"sync":true,"outcome":"success"}}
73
+ {"error":{"id":"err001","timestamp":1709740800000000,"exception":{"message":"Something broke","type":"TypeError","handled":false,"stacktrace":[...]}}}
74
+ {"metricset":{"timestamp":1709740800000000,"samples":{"system.process.cpu.total.norm.pct":{"value":0.023},"nodejs.memory.heap.used.bytes":{"value":52428800}}}}
75
+ {"event":{"type":"page_view","timestamp":1719484200000,"message":"User viewed dashboard","level":"info","user":{"id":"u-abc123","username":"jane_doe"},"client":{"name":"duiduidui-ios","version":"2.4.1","os":{"name":"iOS","version":"18.2"},"device":{"model":"iPhone 16 Pro","type":"phone"}},"params":{"page":"/dashboard"}}}
76
+ ```
77
+
78
+ For the complete schema of every field in each event type, see **[SCHEMA.md](SCHEMA.md)**.
79
+
80
+ ## Configuration
81
+
82
+ All options can be set via `require('tracelog').start({...})`, via environment variables, or in a `tracelog.config.js` file.
83
+
84
+ | Option | Env Var | Default | Description |
85
+ |--------|---------|---------|-------------|
86
+ | `serviceName` | `TRACELOG_SERVICE_NAME` | from package.json | Name of your service |
87
+ | `serviceVersion` | `TRACELOG_SERVICE_VERSION` | from package.json | Version of your service |
88
+ | `environment` | `TRACELOG_ENVIRONMENT` | `NODE_ENV` or `development` | Deployment environment |
89
+ | `logDir` | `TRACELOG_LOG_DIR` | `.` (cwd) | Directory for JSONL output files |
90
+ | `logFilePrefix` | `TRACELOG_LOG_FILE_PREFIX` | `tracelog` | Filename prefix (files are named `{prefix}-{date}.jsonl`) |
91
+ | `logMaxFileSize` | — | `104857600` (100MB) | Rotate when file exceeds this size in bytes |
92
+ | `logRotationSchedule` | `TRACELOG_LOG_ROTATION_SCHEDULE` | `daily` | Time-based rotation: `daily` or `hourly` |
93
+ | `s3Bucket` | `TRACELOG_S3_BUCKET` | — | S3 bucket for log upload (disabled if not set) |
94
+ | `active` | `TRACELOG_ACTIVE` | `true` | Enable/disable the agent entirely |
95
+ | `logLevel` | `TRACELOG_LOG_LEVEL` | `info` | Agent log level |
96
+
97
+ For the complete list of all configuration options (instrumentation, sampling, error capture, stack traces, span compression, metrics, S3 upload, cloud, and more), see **[CONFIG.md](CONFIG.md)**.
98
+
99
+ ## Filtering
100
+
101
+ Filter functions let you modify or drop events before they are written. Return the (possibly modified) object to keep it, or return a falsy value to drop it.
102
+
103
+ ```js
104
+ const apm = require('tracelog').start({ serviceName: 'my-api' });
105
+
106
+ // Drop all debug-level custom events
107
+ apm.addEventFilter((event) => {
108
+ return event.level === 'debug' ? false : event;
109
+ });
110
+
111
+ // Redact user emails from custom events
112
+ apm.addEventFilter((event) => {
113
+ if (event.user) event.user.email = '[REDACTED]';
114
+ return event;
115
+ });
116
+ ```
117
+
118
+ Available filter methods: `addFilter(fn)` (adds to all types), `addTransactionFilter(fn)`, `addSpanFilter(fn)`, `addErrorFilter(fn)`, `addEventFilter(fn)`, `addMetadataFilter(fn)`.
119
+
120
+ ## Auto-instrumented modules
121
+
122
+ Express, Fastify, Koa, Hapi, Connect, Restify, HTTP/HTTPS, fetch/undici, PostgreSQL, MySQL, MongoDB, Redis, Elasticsearch, Cassandra, Memcached, AWS SDK (v2 & v3), GraphQL, Apollo Server, Kafka, WebSockets, generic-pool, Knex, Tedious (MSSQL), Handlebars, Pug, and more.
123
+
124
+ ## License
125
+
126
+ [BSD-2-Clause](LICENSE) — forked from Elastic APM Node.js Agent.
package/index.d.ts ADDED
@@ -0,0 +1,464 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ /// <reference types="node" />
8
+
9
+ // Note: We avoid import of any external `@types/...` to avoid TypeScript users
10
+ // needing to manually install them. The only exception is the prerequisite to
11
+ // `npm install -D @types/node`.
12
+ import type { IncomingMessage, ServerResponse } from 'http';
13
+ import { Connect } from './types/connect';
14
+ import { AwsLambda } from './types/aws-lambda';
15
+
16
+ declare namespace apm {
17
+ // Agent API
18
+ // https://www.elastic.co/guide/en/apm/agent/nodejs/current/agent-api.html
19
+ export interface Agent {
20
+ // Configuration
21
+ start (options?: AgentConfigOptions): Agent;
22
+ isStarted (): boolean;
23
+ getServiceName (): string | undefined;
24
+ getServiceVersion (): string | undefined;
25
+ getServiceEnvironment (): string;
26
+ getServiceNodeName (): string | undefined;
27
+ setFramework (options: {
28
+ name?: string;
29
+ version?: string;
30
+ overwrite?: boolean;
31
+ }): void;
32
+ addPatch (modules: string | Array<string>, handler: string | PatchHandler): void;
33
+ removePatch (modules: string | Array<string>, handler: string | PatchHandler): void;
34
+ clearPatches (modules: string | Array<string>): void;
35
+
36
+ // Data collection hooks
37
+ middleware: { connect (): Connect.ErrorHandleFunction };
38
+ lambda (handler: AwsLambda.Handler): AwsLambda.Handler;
39
+ lambda (type: string, handler: AwsLambda.Handler): AwsLambda.Handler;
40
+ handleUncaughtExceptions (
41
+ fn?: (err: Error) => void
42
+ ): void;
43
+
44
+ // Write methods (primary API)
45
+ writeError (err: Error | string | ParameterizedMessageObject, callback?: CaptureErrorCallback): void;
46
+ writeError (err: Error | string | ParameterizedMessageObject, options?: CaptureErrorOptions, callback?: CaptureErrorCallback): void;
47
+ writeEvent (type: string, options?: CaptureEventOptions, callback?: Function): void;
48
+ writeEvents (events: CaptureEventData[], callback?: Function): void;
49
+ writeTransaction (transaction: object): void;
50
+ writeSpan (span: object): void;
51
+
52
+ // Backward compat aliases
53
+ captureError (err: Error | string | ParameterizedMessageObject, callback?: CaptureErrorCallback): void;
54
+ captureError (err: Error | string | ParameterizedMessageObject, options?: CaptureErrorOptions, callback?: CaptureErrorCallback): void;
55
+ captureEvent (type: string, options?: CaptureEventOptions, callback?: Function): void;
56
+ captureEvents (events: CaptureEventData[], callback?: Function): void;
57
+ writeClientTransaction (transaction: object): void;
58
+ writeClientSpan (span: object): void;
59
+
60
+ // Channels — route records to separate JSONL files
61
+ getChannel (name: string): Channel;
62
+
63
+ // Distributed Tracing
64
+ currentTraceparent: string | null;
65
+ currentTraceIds: {
66
+ 'trace.id'?: string;
67
+ 'transaction.id'?: string;
68
+ 'span.id'?: string;
69
+ }
70
+
71
+ // Transactions
72
+ startTransaction(
73
+ name?: string | null,
74
+ options?: TransactionOptions
75
+ ): Transaction;
76
+ startTransaction(
77
+ name: string | null,
78
+ type: string | null,
79
+ options?: TransactionOptions
80
+ ): Transaction;
81
+ setTransactionName (name: string): void;
82
+ endTransaction (result?: string | number, endTime?: number): void;
83
+ currentTransaction: Transaction | null;
84
+
85
+ // Spans
86
+ startSpan(
87
+ name?: string | null,
88
+ options?: SpanOptions
89
+ ): Span | null;
90
+ startSpan(
91
+ name: string | null,
92
+ type: string | null,
93
+ options?: SpanOptions
94
+ ): Span | null;
95
+ startSpan(
96
+ name: string | null,
97
+ type: string | null,
98
+ subtype: string | null,
99
+ options?: SpanOptions
100
+ ): Span | null;
101
+ startSpan(
102
+ name: string | null,
103
+ type: string | null,
104
+ subtype: string | null,
105
+ action: string | null,
106
+ options?: SpanOptions
107
+ ): Span | null;
108
+ currentSpan: Span | null;
109
+
110
+ // Context
111
+ setGlobalLabel (name: string, value: LabelValue): void;
112
+ setLabel (name: string, value: LabelValue, stringify?: boolean): boolean;
113
+ addLabels (labels: Labels, stringify?: boolean): boolean;
114
+ setUserContext (user: UserObject): void;
115
+ setCustomContext (custom: object): void;
116
+
117
+ // Transport
118
+ addFilter (fn: FilterFn): void;
119
+ addErrorFilter (fn: FilterFn): void;
120
+ addSpanFilter (fn: FilterFn): void;
121
+ addTransactionFilter (fn: FilterFn): void;
122
+ addEventFilter (fn: FilterFn): void;
123
+ addMetadataFilter (fn: FilterFn): void;
124
+ flush (): Promise<void>;
125
+ flush (callback?: Function): void;
126
+ destroy (): Promise<void>;
127
+
128
+ // Utils
129
+ logger: Logger;
130
+
131
+ // Custom metrics
132
+ registerMetric(name: string, callback: Function): void;
133
+ registerMetric(name: string, labels: Labels, callback: Function): void;
134
+
135
+ setTransactionOutcome(outcome: Outcome): void;
136
+ setSpanOutcome(outcome: Outcome): void;
137
+ }
138
+
139
+ type Outcome = 'unknown' | 'success' | 'failure';
140
+
141
+ // Transaction API
142
+ // https://www.elastic.co/guide/en/apm/agent/nodejs/current/transaction-api.html
143
+ export interface Transaction {
144
+ // The following properties and methods are currently not documented as their API isn't considered official:
145
+ // - timestamp, ended, id, traceId, parentId, sampled, duration()
146
+ // - setUserContext(), setCustomContext(), toJSON(), setDefaultName(), setDefaultNameFromRequest()
147
+
148
+ name: string;
149
+ type: string | null;
150
+ traceparent: string;
151
+ outcome: Outcome;
152
+ result: string | number;
153
+ ids: {
154
+ 'trace.id': string;
155
+ 'transaction.id': string;
156
+ }
157
+
158
+ setType (type?: string | null): void;
159
+ setLabel (name: string, value: LabelValue, stringify?: boolean): boolean;
160
+ addLabels (labels: Labels, stringify?: boolean): boolean;
161
+ setOutcome(outcome: Outcome): void;
162
+ addLink (link: Link): void;
163
+ addLinks (links: Link[]): void;
164
+
165
+ startSpan(
166
+ name?: string | null,
167
+ options?: SpanOptions
168
+ ): Span | null;
169
+ startSpan(
170
+ name: string | null,
171
+ type: string | null,
172
+ options?: SpanOptions
173
+ ): Span | null;
174
+ startSpan(
175
+ name: string | null,
176
+ type: string | null,
177
+ subtype: string | null,
178
+ options?: SpanOptions
179
+ ): Span | null;
180
+ startSpan(
181
+ name: string | null,
182
+ type: string | null,
183
+ subtype: string | null,
184
+ action: string | null,
185
+ options?: SpanOptions
186
+ ): Span | null;
187
+ ensureParentId (): string;
188
+ end (result?: string | number | null, endTime?: number): void;
189
+ }
190
+
191
+ // Span API
192
+ // https://www.elastic.co/guide/en/apm/agent/nodejs/current/span-api.html
193
+ export interface Span {
194
+ // The following properties and methods are currently not documented as their API isn't considered official:
195
+ // - timestamp, ended, id, traceId, parentId, sampled, duration()
196
+ // - customStackTrace(), setDbContext()
197
+
198
+ transaction: Transaction;
199
+ name: string;
200
+ type: string | null;
201
+ subtype: string | null;
202
+ action: string | null;
203
+ traceparent: string;
204
+ outcome: Outcome;
205
+ ids: {
206
+ 'trace.id': string;
207
+ 'span.id': string;
208
+ }
209
+
210
+ setType (type?: string | null, subtype?: string | null, action?: string | null): void;
211
+ setLabel (name: string, value: LabelValue, stringify?: boolean): boolean;
212
+ addLabels (labels: Labels, stringify?: boolean): boolean;
213
+ setOutcome(outcome: Outcome): void;
214
+ setServiceTarget(type?: string | null, name?: string | null): void;
215
+ addLink (link: Link): void;
216
+ addLinks (links: Link[]): void;
217
+ end (endTime?: number): void;
218
+ }
219
+
220
+ // https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html
221
+ export interface AgentConfigOptions {
222
+ abortedErrorThreshold?: string; // Also support `number`, but as we're removing this functionality soon, there's no need to advertise it
223
+ active?: boolean;
224
+ addPatch?: KeyValueConfig;
225
+ apiKey?: string;
226
+ apiRequestSize?: string; // Also support `number`, but as we're removing this functionality soon, there's no need to advertise it
227
+ apiRequestTime?: string; // Also support `number`, but as we're removing this functionality soon, there's no need to advertise it
228
+ breakdownMetrics?: boolean;
229
+ captureBody?: CaptureBody;
230
+ captureErrorLogStackTraces?: CaptureErrorLogStackTraces;
231
+ captureExceptions?: boolean;
232
+ captureHeaders?: boolean;
233
+ /**
234
+ * @deprecated Use `spanStackTraceMinDuration`.
235
+ */
236
+ captureSpanStackTraces?: boolean;
237
+ centralConfig?: boolean;
238
+ cloudProvider?: string;
239
+ configFile?: string;
240
+ containerId?: string;
241
+ contextManager?: string;
242
+ contextPropagationOnly?: boolean;
243
+ disableInstrumentations?: string | string[];
244
+ disableSend?: boolean;
245
+ elasticsearchCaptureBodyUrls?: Array<string>;
246
+ environment?: string;
247
+ /**
248
+ * @deprecated Use `longFieldMaxLength`
249
+ */
250
+ errorMessageMaxLength?: string;
251
+ errorOnAbortedRequests?: boolean;
252
+ exitSpanMinDuration?: string;
253
+ frameworkName?: string;
254
+ frameworkVersion?: string;
255
+ globalLabels?: KeyValueConfig;
256
+ hostname?: string;
257
+ ignoreMessageQueues?: Array<string>;
258
+ ignoreUrls?: Array<string | RegExp>;
259
+ ignoreUserAgents?: Array<string | RegExp>;
260
+ instrument?: boolean;
261
+ instrumentIncomingHTTPRequests?: boolean;
262
+ kubernetesNamespace?: string;
263
+ kubernetesNodeName?: string;
264
+ kubernetesPodName?: string;
265
+ kubernetesPodUID?: string;
266
+ logLevel?: LogLevel;
267
+ logger?: Logger; // Notably this Logger interface matches the Pino Logger.
268
+ longFieldMaxLength?: number;
269
+ maxQueueSize?: number;
270
+ metricsInterval?: string; // Also support `number`, but as we're removing this functionality soon, there's no need to advertise it
271
+ metricsLimit?: number;
272
+ opentelemetryBridgeEnabled?: boolean;
273
+ payloadLogFile?: string;
274
+ sanitizeFieldNames?: Array<string>;
275
+ secretToken?: string;
276
+ serverCaCertFile?: string;
277
+ serverTimeout?: string; // Also support `number`, but as we're removing this functionality soon, there's no need to advertise it
278
+ serverUrl?: string;
279
+ serviceName?: string;
280
+ serviceNodeName?: string;
281
+ serviceVersion?: string;
282
+ sourceLinesErrorAppFrames?: number;
283
+ sourceLinesErrorLibraryFrames?: number;
284
+ sourceLinesSpanAppFrames?: number;
285
+ sourceLinesSpanLibraryFrames?: number;
286
+ spanCompressionEnabled?: boolean;
287
+ spanCompressionExactMatchMaxDuration?: string;
288
+ spanCompressionSameKindMaxDuration?: string;
289
+ /**
290
+ * @deprecated Use `spanStackTraceMinDuration`.
291
+ */
292
+ spanFramesMinDuration?: string;
293
+ spanStackTraceMinDuration?: string;
294
+ stackTraceLimit?: number;
295
+ traceContinuationStrategy?: TraceContinuationStrategy;
296
+ transactionIgnoreUrls?: Array<string>;
297
+ transactionMaxSpans?: number;
298
+ transactionSampleRate?: number;
299
+ useElasticTraceparentHeader?: boolean;
300
+ usePathAsTransactionName?: boolean;
301
+ verifyServerCert?: boolean;
302
+
303
+ // Tracelog: output & rotation
304
+ logDir?: string;
305
+ logFilePrefix?: string;
306
+ logMaxFileSize?: number;
307
+ logFlushIntervalMs?: number;
308
+ logRotationSchedule?: 'daily' | 'hourly' | string;
309
+ maxLocalRetentionDays?: number;
310
+ maxBufferSize?: number;
311
+
312
+ // Tracelog: S3 upload
313
+ s3Bucket?: string;
314
+ s3Region?: string;
315
+ s3KeyTemplate?: string;
316
+ s3UploadIntervalMs?: number;
317
+ s3GzipCompleted?: boolean;
318
+ s3GzipCurrent?: boolean;
319
+ s3AccessKeyId?: string;
320
+ s3SecretAccessKey?: string;
321
+ s3SessionToken?: string;
322
+ }
323
+
324
+ interface Channel {
325
+ writeEvent (type: string, options?: CaptureEventOptions, callback?: Function): void;
326
+ writeEvents (events: CaptureEventData[], callback?: Function): void;
327
+ writeError (err: Error | string | ParameterizedMessageObject, options?: CaptureErrorOptions, callback?: CaptureErrorCallback): void;
328
+ writeTransaction (transaction: object): void;
329
+ writeSpan (span: object): void;
330
+ }
331
+
332
+ interface CaptureEventOptions {
333
+ message?: string;
334
+ level?: 'debug' | 'info' | 'warn' | 'error' | 'fatal';
335
+ timestamp?: number;
336
+ duration?: number;
337
+ error?: Error | any;
338
+ user?: EventUserInfo;
339
+ client?: EventClientInfo;
340
+ params?: { [key: string]: any };
341
+ }
342
+
343
+ interface CaptureEventData extends CaptureEventOptions {
344
+ type: string;
345
+ }
346
+
347
+ interface EventUserInfo {
348
+ id?: string;
349
+ email?: string;
350
+ username?: string;
351
+ }
352
+
353
+ interface EventClientInfo {
354
+ name?: string;
355
+ version?: string;
356
+ os?: { name?: string; version?: string };
357
+ device?: { model?: string; type?: string };
358
+ runtime?: { name?: string; version?: string };
359
+ }
360
+
361
+ interface CaptureErrorOptions {
362
+ request?: IncomingMessage;
363
+ response?: ServerResponse;
364
+ timestamp?: number;
365
+ handled?: boolean;
366
+ user?: UserObject;
367
+ labels?: Labels;
368
+ tags?: Labels;
369
+ custom?: object;
370
+ message?: string;
371
+ captureAttributes?: boolean;
372
+ skipOutcome?: boolean;
373
+ /**
374
+ * A Transaction or Span instance to make the parent of this error. If not
375
+ * given (undefined), then the current span or transaction will be used. If
376
+ * `null` is given, then no span or transaction will be used.
377
+ */
378
+ parent?: Transaction | Span | null;
379
+ }
380
+
381
+ interface Labels {
382
+ [key: string]: LabelValue;
383
+ }
384
+
385
+ interface UserObject {
386
+ id?: string | number;
387
+ username?: string;
388
+ email?: string;
389
+ }
390
+
391
+ interface ParameterizedMessageObject {
392
+ message: string;
393
+ params: Array<any>;
394
+ }
395
+
396
+ interface Logger {
397
+ // Defining overloaded methods rather than a separate `interface LogFn`
398
+ // as @types/pino does, because the IDE completion shows these as *methods*
399
+ // rather than as properties, which is slightly nicer.
400
+ fatal (msg: string, ...args: any[]): void;
401
+ fatal (obj: {}, msg?: string, ...args: any[]): void;
402
+ error (msg: string, ...args: any[]): void;
403
+ error (obj: {}, msg?: string, ...args: any[]): void;
404
+ warn (msg: string, ...args: any[]): void;
405
+ warn (obj: {}, msg?: string, ...args: any[]): void;
406
+ info (msg: string, ...args: any[]): void;
407
+ info (obj: {}, msg?: string, ...args: any[]): void;
408
+ debug (msg: string, ...args: any[]): void;
409
+ debug (obj: {}, msg?: string, ...args: any[]): void;
410
+ trace (msg: string, ...args: any[]): void;
411
+ trace (obj: {}, msg?: string, ...args: any[]): void;
412
+ // Allow a passed in Logger that has other properties, as a Pino logger
413
+ // does. Discussion:
414
+ // https://github.com/elastic/apm-agent-nodejs/pull/926/files#r266239656
415
+ [propName: string]: any;
416
+ }
417
+
418
+ // Link and `links` are intended to be compatible with OTel's
419
+ // equivalent APIs in "opentelemetry-js-api/src/trace/link.ts". Currently
420
+ // span link attributes are not supported.
421
+ export interface Link {
422
+ /** A W3C trace-context 'traceparent' string, Transaction, Span, or OTel SpanContext. */
423
+ context: Transaction | Span | {traceId: string, spanId: string} | string;
424
+ }
425
+
426
+ export interface TransactionOptions {
427
+ startTime?: number;
428
+ // `childOf` is a W3C trace-context 'traceparent' string. Passing a
429
+ // Transaction or Span is deprecated.
430
+ childOf?: Transaction | Span | string;
431
+ tracestate?: string; // A W3C trace-context 'tracestate' string.
432
+ links?: Link[];
433
+ }
434
+
435
+ export interface SpanOptions {
436
+ startTime?: number;
437
+ childOf?: Transaction | Span | string;
438
+ exitSpan?: boolean;
439
+ links?: Link[];
440
+ }
441
+
442
+ type CaptureBody = 'off' | 'errors' | 'transactions' | 'all';
443
+ type CaptureErrorLogStackTraces = 'never' | 'messages' | 'always';
444
+ type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'warning' | 'error' | 'fatal' | 'critical' | 'off';
445
+ type TraceContinuationStrategy = 'continue' | 'restart' | 'restart_external';
446
+
447
+ type CaptureErrorCallback = (err: Error | null, id: string) => void;
448
+ type FilterFn = (payload: Payload) => Payload | boolean | void;
449
+ type LabelValue = string | number | boolean | null | undefined;
450
+ type KeyValueConfig = string | Labels | Array<Array<LabelValue>>
451
+
452
+ type Payload = { [propName: string]: any }
453
+
454
+ type PatchHandler = (exports: any, agent: Agent, options: PatchOptions) => any;
455
+
456
+ interface PatchOptions {
457
+ name: string;
458
+ version: string | undefined;
459
+ enabled: boolean;
460
+ }
461
+ }
462
+
463
+ declare const apm: apm.Agent;
464
+ export = apm;
package/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ var Agent = require('./lib/agent');
10
+
11
+ module.exports = new Agent();
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ // A `Set` object used to track inflight APM events: ended spans and errors
10
+ // that are currently being processed, but have not yet been sent to the Agent
11
+ // transport.
12
+ //
13
+ // `setDrainHandler` allows setting a function to be called when the inflight
14
+ // events have drained. Agent#flush() uses this to ensure that a flush waits
15
+ // for inflight events to be processed, so they are sent to APM Server before
16
+ // calling back.
17
+ class InflightEventSet extends Set {
18
+ // Set a `fn` to be called *once* when the set size next goes to zero.
19
+ // If the optional `timeoutMs` is given, then `fn(err)` will be called if
20
+ // the set hasn't yet drained.
21
+ setDrainHandler(fn, timeoutMs) {
22
+ this._drainHandler = fn;
23
+ if (timeoutMs) {
24
+ this._drainTimeout = setTimeout(() => {
25
+ this._drain(new Error('inflight event set drain timeout'));
26
+ }, timeoutMs).unref();
27
+ }
28
+ }
29
+
30
+ // Call the drain handler, if there is one.
31
+ _drain(err) {
32
+ if (this._drainHandler) {
33
+ if (this._drainTimeout) {
34
+ clearTimeout(this._drainTimeout);
35
+ this._drainTimeout = null;
36
+ }
37
+ this._drainHandler(err);
38
+ // Remove the handler so it is only called once.
39
+ this._drainHandler = null;
40
+ }
41
+ }
42
+
43
+ delete(key) {
44
+ super.delete(key);
45
+ if (this.size === 0) {
46
+ this._drain();
47
+ }
48
+ }
49
+ }
50
+
51
+ module.exports = {
52
+ InflightEventSet,
53
+ };