autotel-mongoose 8.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -77,6 +77,117 @@ userSchema.pre('save', async function () {
77
77
  });
78
78
  ```
79
79
 
80
+ ## Custom Statics, Methods & Query Helpers
81
+
82
+ The functions you add via `schema.statics`, `schema.methods`, and `schema.query`
83
+ are invisible to the built-in Model/Query instrumentation. This package traces
84
+ them automatically — **no manual `trace()` calls** and no behavioral side
85
+ effects (same `this`, same return value, same error propagation). Each call
86
+ gets an `INTERNAL` span named `mongoose.<Model>.<fn>`.
87
+
88
+ ```typescript
89
+ userSchema.statics.findByEmail = function (email: string) {
90
+ return this.findOne({ email }); // span: mongoose.User.findByEmail
91
+ };
92
+
93
+ userSchema.methods.describe = function () {
94
+ return `${this.name} <${this.email}>`; // span: mongoose.User.describe
95
+ };
96
+
97
+ userSchema.query.byEmailDomain = function (domain: string) {
98
+ return this.where({ email: new RegExp(`@${domain}$`) }); // span: mongoose.User.byEmailDomain
99
+ };
100
+ ```
101
+
102
+ Example spans (from `apps/example-mongoose`, debug output). Note that a static
103
+ returning a Query becomes the **parent** of the underlying operation span, and
104
+ parameters are redacted by default:
105
+
106
+ ```text
107
+ ✓ findOne users 1ms [autotel-mongoose]
108
+ db.system.name=mongodb, db.operation.name=findOne, db.collection.name=users, db.query.text={"condition":{"email":"A***@***.com"},...
109
+ ✓ mongoose.User.findByEmail 2ms [autotel-mongoose]
110
+ db.system.name=mongodb, code.function.name=findByEmail, mongoose.method.name=findByEmail, mongoose.method.type=static, mongoose.method.model=User, db.collection.name=users, mongoose.method.parameter_count=1, mongoose.method.parameters=["A***@***.com"]
111
+
112
+ ✓ mongoose.User.describe 27µs [autotel-mongoose]
113
+ db.system.name=mongodb, code.function.name=describe, mongoose.method.name=describe, mongoose.method.type=instance, mongoose.method.model=User, db.collection.name=users, mongoose.method.parameter_count=0
114
+
115
+ ✓ mongoose.User.countByDomain 2ms [autotel-mongoose]
116
+ db.system.name=mongodb, code.function.name=countByDomain, mongoose.method.name=countByDomain, mongoose.method.type=static, mongoose.method.model=User, db.collection.name=users, mongoose.method.parameter_count=1, mongoose.method.parameters=["hotmail.com"]
117
+
118
+ ✓ mongoose.User.byEmailDomain 82µs [autotel-mongoose]
119
+ db.system.name=mongodb, code.function.name=byEmailDomain, mongoose.method.name=byEmailDomain, mongoose.method.type=query, mongoose.method.model=User, db.collection.name=users, mongoose.method.parameter_count=1, mongoose.method.parameters=["hotmail.com"]
120
+ ```
121
+
122
+ As JSON:
123
+
124
+ ```json
125
+ {
126
+ "name": "mongoose.User.findByEmail",
127
+ "kind": "INTERNAL",
128
+ "instrumentationScope": { "name": "autotel-mongoose" },
129
+ "attributes": {
130
+ "db.system.name": "mongodb",
131
+ "code.function.name": "findByEmail",
132
+ "mongoose.method.name": "findByEmail",
133
+ "mongoose.method.type": "static",
134
+ "mongoose.method.model": "User",
135
+ "db.collection.name": "users",
136
+ "mongoose.method.parameter_count": 1,
137
+ "mongoose.method.parameters": "[\"A***@***.com\"]"
138
+ }
139
+ }
140
+ ```
141
+
142
+ Span attributes: `mongoose.method.name`, `mongoose.method.type`
143
+ (`static` | `instance` | `query`), `mongoose.method.model`, `code.function.name`,
144
+ and — when parameter capture is on — `mongoose.method.parameters` (+
145
+ `mongoose.method.parameter_count`).
146
+
147
+ > **Behavior note (default on):** With no `customMethods` option, `instrumentMongoose(mongoose)`
148
+ > wraps **all** custom functions and captures their arguments by default
149
+ > (maximum observability). Arguments pass through the same redactor as
150
+ > `db.query.text`, but custom-function args are often business payloads rather
151
+ > than DB filters — redaction won't catch arbitrary fields. Use the options
152
+ > below to scope this down for privacy/compliance.
153
+
154
+ ### Opting out / scoping (privacy & compliance)
155
+
156
+ ```typescript
157
+ // Disable entirely
158
+ instrumentMongoose(mongoose, { customMethods: false });
159
+
160
+ // Per-category control. Anything not explicitly disabled stays on.
161
+ instrumentMongoose(mongoose, {
162
+ customMethods: {
163
+ statics: { exclude: ['chargeCard'] }, // opt-out specific statics
164
+ methods: ['describe'], // opt-in: only these instance methods
165
+ query: false, // no query helpers
166
+ captureParameters: false, // trace calls, don't serialize args
167
+ },
168
+ });
169
+
170
+ // Keep tracing, but never serialize arguments anywhere
171
+ instrumentMongoose(mongoose, { customMethods: { captureParameters: false } });
172
+
173
+ // Custom parameter serializer / longer cap / dedicated redactor
174
+ instrumentMongoose(mongoose, {
175
+ customMethods: {
176
+ captureParameters: {
177
+ maxLength: 4096,
178
+ redactor: 'default',
179
+ serializer: (args, { methodName }) =>
180
+ methodName === 'chargeCard' ? undefined : JSON.stringify(args),
181
+ },
182
+ },
183
+ });
184
+ ```
185
+
186
+ A selector accepts `true` (all), `false` (none), `string[]` (opt-in to those
187
+ names), or `{ include?, exclude? }`. Config is resolved **per Mongoose
188
+ instance** at call time, so a schema object reused across multiple
189
+ instances/connections honors each instance's own configuration.
190
+
80
191
  ## Configuration
81
192
 
82
193
  ```typescript
@@ -91,6 +202,7 @@ const config: InstrumentMongooseConfig = {
91
202
  instrumentHooks: false,
92
203
  dbStatementSerializer: false,
93
204
  statementRedactor: 'default',
205
+ customMethods: true, // wrap all custom statics/methods/query helpers (default)
94
206
  };
95
207
  ```
96
208
 
@@ -137,13 +249,15 @@ instrumentMongoose(mongoose, {
137
249
  - `instrumentMongoose(mongoose, config?)`
138
250
  - `InstrumentMongooseConfig`
139
251
  - `SerializerPayload`
252
+ - `CustomMethodsConfig`, `CustomMethodType`, `MethodSelector`, `ParameterCaptureConfig`
140
253
 
141
254
  ## Notes
142
255
 
143
256
  - Query and aggregate operations are traced automatically
144
257
  - Instance methods like `save()` and `deleteOne()` are traced
145
258
  - Static methods like `create()`, `insertMany()`, `aggregate()`, and `bulkWrite()` are traced
146
- - Hook spans use `SpanKind.INTERNAL`
259
+ - User-defined statics, instance methods, and query helpers are traced automatically (see above)
260
+ - Hook and custom-function spans use `SpanKind.INTERNAL`
147
261
 
148
262
  ## License
149
263