-
Notifications
You must be signed in to change notification settings - Fork 433
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: change to per-product usageV2 topic #6113
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import type { ServiceName } from "src/node/index.js"; | ||
|
||
export interface UsageV2Event { | ||
/** | ||
* A unique identifier for the event. Defaults to a random UUID. | ||
|
@@ -8,10 +10,6 @@ export interface UsageV2Event { | |
* The event timestamp. Defaults to now(). | ||
*/ | ||
created_at?: Date; | ||
/** | ||
* The source of the event. Example: "storage" | ||
*/ | ||
source: string; | ||
/** | ||
* The action of the event. Example: "upload" | ||
*/ | ||
|
@@ -49,8 +47,12 @@ export interface UsageV2Event { | |
*/ | ||
product_version?: string; | ||
/** | ||
* An object of service-specific data. Example: "file_size_bytes" | ||
* It is safe to pass any new JSON-serializable data here before updating the usageV2 schema. | ||
* An object of arbitrary key-value pairs. | ||
* Values can be boolean, number, string, Date, or null. | ||
*/ | ||
data: Record<string, unknown>; | ||
[key: string]: boolean | number | string | Date | null | undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using an index signature here could cause TypeScript to miss type errors on the explicitly defined properties in Spotted by Graphite Reviewer |
||
} | ||
|
||
export function getTopicName(productName: ServiceName) { | ||
return `usage_v2.raw_${productName}`; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,8 @@ | ||
import { randomUUID } from "node:crypto"; | ||
import { checkServerIdentity } from "node:tls"; | ||
import { Kafka, type Producer } from "kafkajs"; | ||
import type { UsageV2Event } from "../core/usageV2.js"; | ||
|
||
const TOPIC_USAGE_V2 = "usage_v2.raw_events"; | ||
import type { ServiceName } from "src/core/services.js"; | ||
import { type UsageV2Event, getTopicName } from "../core/usageV2.js"; | ||
|
||
/** | ||
* Creates a UsageV2Producer which opens a persistent TCP connection. | ||
|
@@ -21,6 +20,7 @@ const TOPIC_USAGE_V2 = "usage_v2.raw_events"; | |
export class UsageV2Producer { | ||
private kafka: Kafka; | ||
private producer: Producer | null = null; | ||
private productName: ServiceName; | ||
|
||
constructor(config: { | ||
/** | ||
|
@@ -31,6 +31,10 @@ export class UsageV2Producer { | |
* The environment the service is running in. | ||
*/ | ||
environment: "development" | "production"; | ||
/** | ||
* The product "source" where usage is coming from. | ||
*/ | ||
productName: ServiceName; | ||
|
||
username: string; | ||
password: string; | ||
|
@@ -52,6 +56,8 @@ export class UsageV2Producer { | |
password: config.password, | ||
}, | ||
}); | ||
|
||
this.productName = config.productName; | ||
} | ||
|
||
/** | ||
|
@@ -82,27 +88,18 @@ export class UsageV2Producer { | |
|
||
const parsedEvents = events.map((event) => { | ||
return { | ||
...event, | ||
id: event.id ?? randomUUID(), | ||
created_at: event.created_at ?? new Date(), | ||
source: event.source, | ||
action: event.action, | ||
// Remove the "team_" prefix, if any. | ||
team_id: event.team_id.startsWith("team_") | ||
? event.team_id.slice(5) | ||
: event.team_id, | ||
project_id: event.project_id, | ||
sdk_name: event.sdk_name, | ||
sdk_platform: event.sdk_platform, | ||
sdk_version: event.sdk_version, | ||
sdk_os: event.sdk_os, | ||
product_name: event.product_name, | ||
product_version: event.product_version, | ||
data: JSON.stringify(event.data), | ||
}; | ||
Comment on lines
90
to
98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider moving return {
id: event.id ?? randomUUID(),
created_at: event.created_at ?? new Date(),
team_id: event.team_id.startsWith("team_")
? event.team_id.slice(5)
: event.team_id,
...event
}; Spotted by Graphite Reviewer |
||
}); | ||
|
||
await this.producer.send({ | ||
topic: TOPIC_USAGE_V2, | ||
topic: getTopicName(this.productName), | ||
messages: parsedEvents.map((event) => ({ | ||
value: JSON.stringify(event), | ||
})), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer needed because events are sent to product-specific topics (and stored to product-specific tables).