convex-tracer 0.1.0 → 0.1.2

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.
@@ -2,15 +2,16 @@
2
2
  * Internal mutations for managing traces, spans, and logs.
3
3
  * These are called automatically by the tracing system to persist data immediately.
4
4
  */
5
+ import { paginationOptsValidator } from "convex/server";
5
6
  import { v } from "convex/values";
6
7
  import type { Id } from "./_generated/dataModel.js";
7
8
  import { mutation, query, type MutationCtx } from "./_generated/server.js";
8
- import schema, {
9
+ import {
9
10
  severityValidator,
10
11
  sourceValidator,
11
12
  statusValidator,
12
13
  } from "./schema.js";
13
- import { vCompleteTrace } from "./types.js";
14
+ import { vCompleteTrace, vPaginatedTraces } from "./types.js";
14
15
 
15
16
  // ============================================================================
16
17
  // Trace Operations
@@ -26,6 +27,7 @@ export const createTrace = mutation({
26
27
  sampleRate: v.number(),
27
28
  metadata: v.optional(v.record(v.string(), v.any())),
28
29
  source: sourceValidator,
30
+ userId: v.union(v.literal("anonymous"), v.string()),
29
31
  },
30
32
  returns: v.id("traces"),
31
33
  handler: async (ctx, args): Promise<Id<"traces">> => {
@@ -34,6 +36,7 @@ export const createTrace = mutation({
34
36
  sampleRate: args.sampleRate,
35
37
  updatedAt: Date.now(),
36
38
  metadata: args.metadata,
39
+ userId: args.userId,
37
40
  });
38
41
  },
39
42
  });
@@ -305,34 +308,75 @@ export const getTrace = query({
305
308
  export const listTraces = query({
306
309
  args: {
307
310
  status: v.optional(statusValidator),
308
- limit: v.optional(v.number()),
309
311
  userId: v.optional(v.string()),
312
+ paginationOpts: paginationOptsValidator,
310
313
  },
311
- returns: v.array(
312
- schema.tables.traces.validator.extend({
313
- _id: v.id("traces"),
314
- _creationTime: v.number(),
315
- }),
316
- ),
317
- handler: async (ctx, { status, limit, userId }) => {
318
- const query =
319
- status && !userId
320
- ? ctx.db
321
- .query("traces")
322
- .withIndex("by_status", (q) => q.eq("status", status))
323
- : !status && userId
324
- ? ctx.db
325
- .query("traces")
326
- .withIndex("by_userId", (q) => q.eq("userId", userId))
327
- : status && userId
328
- ? ctx.db
329
- .query("traces")
330
- .withIndex("by_status_and_userId", (q) =>
331
- q.eq("status", status).eq("userId", userId),
332
- )
333
- : ctx.db.query("traces");
334
-
335
- return await query.order("desc").take(limit ?? 100);
314
+ returns: vPaginatedTraces,
315
+ handler: async (ctx, { status, userId, paginationOpts }) => {
316
+ const query = ctx.db.query("traces");
317
+
318
+ if (status && !userId) {
319
+ return await query
320
+ .withIndex("by_status", (q) => q.eq("status", status))
321
+ .order("desc")
322
+ .paginate(paginationOpts);
323
+ } else if (!status && userId) {
324
+ return await query
325
+ .withIndex("by_userId", (q) => q.eq("userId", userId))
326
+ .order("desc")
327
+ .paginate(paginationOpts);
328
+ } else if (status && userId) {
329
+ return await query
330
+ .withIndex("by_status_and_userId", (q) =>
331
+ q.eq("status", status).eq("userId", userId),
332
+ )
333
+ .order("desc")
334
+ .paginate(paginationOpts);
335
+ }
336
+
337
+ return await query.order("desc").paginate(paginationOpts);
338
+ },
339
+ });
340
+
341
+ export const searchTraces = query({
342
+ args: {
343
+ functionName: v.string(),
344
+ userId: v.optional(v.string()),
345
+ status: v.optional(statusValidator),
346
+ paginationOpts: paginationOptsValidator,
347
+ },
348
+ returns: vPaginatedTraces,
349
+ handler: async (ctx, { functionName, paginationOpts, userId, status }) => {
350
+ const query = ctx.db.query("traces");
351
+
352
+ if (userId && !status) {
353
+ return await query
354
+ .withSearchIndex("by_function_name", (q) =>
355
+ q.search("functionName", functionName).eq("userId", userId),
356
+ )
357
+ .paginate(paginationOpts);
358
+ } else if (status && !userId) {
359
+ return await query
360
+ .withSearchIndex("by_function_name", (q) =>
361
+ q.search("functionName", functionName).eq("status", status),
362
+ )
363
+ .paginate(paginationOpts);
364
+ } else if (userId && status) {
365
+ return await query
366
+ .withSearchIndex("by_function_name", (q) =>
367
+ q
368
+ .search("functionName", functionName)
369
+ .eq("userId", userId)
370
+ .eq("status", status),
371
+ )
372
+ .paginate(paginationOpts);
373
+ }
374
+
375
+ return await query
376
+ .withSearchIndex("by_function_name", (q) =>
377
+ q.search("functionName", functionName),
378
+ )
379
+ .paginate(paginationOpts);
336
380
  },
337
381
  });
338
382
 
@@ -25,11 +25,16 @@ export default defineSchema({
25
25
  preserve: v.optional(v.boolean()),
26
26
  updatedAt: v.number(),
27
27
  metadata: v.optional(v.record(v.string(), v.any())),
28
+ functionName: v.optional(v.string()),
28
29
  userId: v.optional(v.string()),
29
30
  })
30
31
  .index("by_status", ["status"])
31
32
  .index("by_userId", ["userId"])
32
- .index("by_status_and_userId", ["status", "userId"]),
33
+ .index("by_status_and_userId", ["status", "userId"])
34
+ .searchIndex("by_function_name", {
35
+ searchField: "functionName",
36
+ filterFields: ["status", "userId"],
37
+ }),
33
38
 
34
39
  spans: defineTable({
35
40
  traceId: v.id("traces"),
@@ -1,3 +1,4 @@
1
+ import { paginationResultValidator } from "convex/server";
1
2
  import { v, type Infer } from "convex/values";
2
3
  import schema from "./schema";
3
4
 
@@ -6,6 +7,8 @@ export const vTrace = schema.tables.traces.validator.extend({
6
7
  _creationTime: v.number(),
7
8
  });
8
9
 
10
+ export const vPaginatedTraces = paginationResultValidator(vTrace);
11
+
9
12
  export const vSpan = schema.tables.spans.validator
10
13
  .omit("parentSpanId")
11
14
  .omit("traceId")
@@ -36,3 +39,4 @@ export type Span = Infer<typeof vSpan>;
36
39
  export type Log = Infer<typeof vLog>;
37
40
  export type SpanWithLogs = Infer<typeof vSpanWithLogs>;
38
41
  export type CompleteTrace = Infer<typeof vCompleteTrace>;
42
+ export type paginatedTraces = Infer<typeof vPaginatedTraces>;