Skip to content

Commit 6818cba

Browse files
authored
chore: change to per-product usageV2 topic (#6113)
1 parent a7fb844 commit 6818cba

File tree

4 files changed

+30
-23
lines changed

4 files changed

+30
-23
lines changed

.changeset/pink-melons-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": patch
3+
---
4+
5+
Change UsageV2 to per-product topics

packages/service-utils/src/cf-worker/usageV2.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { UsageV2Event } from "../core/usageV2.js";
1+
import type { ServiceName } from "../core/services.js";
2+
import { type UsageV2Event, getTopicName } from "../core/usageV2.js";
23

34
/**
45
* Send events to Kafka.
@@ -19,6 +20,7 @@ export async function sendUsageV2Events(
1920
events: UsageV2Event[],
2021
options: {
2122
environment: "development" | "production";
23+
productName: ServiceName;
2224
serviceKey: string;
2325
},
2426
): Promise<void> {
@@ -27,7 +29,8 @@ export async function sendUsageV2Events(
2729
? "https://u.thirdweb.com"
2830
: "https://u.thirdweb-dev.com";
2931

30-
const resp = await fetch(`${baseUrl}/usage-v2/raw-events`, {
32+
const topic = getTopicName(options.productName);
33+
const resp = await fetch(`${baseUrl}/usage-v2/${topic}`, {
3134
method: "POST",
3235
headers: {
3336
"Content-Type": "application/json",

packages/service-utils/src/core/usageV2.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { ServiceName } from "../node/index.js";
2+
13
export interface UsageV2Event {
24
/**
35
* A unique identifier for the event. Defaults to a random UUID.
@@ -8,10 +10,6 @@ export interface UsageV2Event {
810
* The event timestamp. Defaults to now().
911
*/
1012
created_at?: Date;
11-
/**
12-
* The source of the event. Example: "storage"
13-
*/
14-
source: string;
1513
/**
1614
* The action of the event. Example: "upload"
1715
*/
@@ -49,8 +47,12 @@ export interface UsageV2Event {
4947
*/
5048
product_version?: string;
5149
/**
52-
* An object of service-specific data. Example: "file_size_bytes"
53-
* It is safe to pass any new JSON-serializable data here before updating the usageV2 schema.
50+
* An object of arbitrary key-value pairs.
51+
* Values can be boolean, number, string, Date, or null.
5452
*/
55-
data: Record<string, unknown>;
53+
[key: string]: boolean | number | string | Date | null | undefined;
54+
}
55+
56+
export function getTopicName(productName: ServiceName) {
57+
return `usage_v2.raw_${productName}`;
5658
}

packages/service-utils/src/node/usageV2.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { randomUUID } from "node:crypto";
22
import { checkServerIdentity } from "node:tls";
33
import { Kafka, type Producer } from "kafkajs";
4-
import type { UsageV2Event } from "../core/usageV2.js";
5-
6-
const TOPIC_USAGE_V2 = "usage_v2.raw_events";
4+
import type { ServiceName } from "../core/services.js";
5+
import { type UsageV2Event, getTopicName } from "../core/usageV2.js";
76

87
/**
98
* Creates a UsageV2Producer which opens a persistent TCP connection.
@@ -21,6 +20,7 @@ const TOPIC_USAGE_V2 = "usage_v2.raw_events";
2120
export class UsageV2Producer {
2221
private kafka: Kafka;
2322
private producer: Producer | null = null;
23+
private topic: string;
2424

2525
constructor(config: {
2626
/**
@@ -31,6 +31,10 @@ export class UsageV2Producer {
3131
* The environment the service is running in.
3232
*/
3333
environment: "development" | "production";
34+
/**
35+
* The product "source" where usage is coming from.
36+
*/
37+
productName: ServiceName;
3438

3539
username: string;
3640
password: string;
@@ -52,6 +56,8 @@ export class UsageV2Producer {
5256
password: config.password,
5357
},
5458
});
59+
60+
this.topic = getTopicName(config.productName);
5561
}
5662

5763
/**
@@ -82,27 +88,18 @@ export class UsageV2Producer {
8288

8389
const parsedEvents = events.map((event) => {
8490
return {
91+
...event,
8592
id: event.id ?? randomUUID(),
8693
created_at: event.created_at ?? new Date(),
87-
source: event.source,
88-
action: event.action,
8994
// Remove the "team_" prefix, if any.
9095
team_id: event.team_id.startsWith("team_")
9196
? event.team_id.slice(5)
9297
: event.team_id,
93-
project_id: event.project_id,
94-
sdk_name: event.sdk_name,
95-
sdk_platform: event.sdk_platform,
96-
sdk_version: event.sdk_version,
97-
sdk_os: event.sdk_os,
98-
product_name: event.product_name,
99-
product_version: event.product_version,
100-
data: JSON.stringify(event.data),
10198
};
10299
});
103100

104101
await this.producer.send({
105-
topic: TOPIC_USAGE_V2,
102+
topic: this.topic,
106103
messages: parsedEvents.map((event) => ({
107104
value: JSON.stringify(event),
108105
})),

0 commit comments

Comments
 (0)