File size: 4,340 Bytes
f8b5d42 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
const { v4 } = require("uuid");
const { SystemSettings } = require("./systemSettings");
// Map of events and last sent time to check if the event is on cooldown
// This will be cleared on server restart - but that is fine since it is mostly to just
// prevent spamming the logs.
const TelemetryCooldown = new Map();
const Telemetry = {
// Write-only key. It can't read events or any of your other data, so it's safe to use in public apps.
pubkey: "phc_9qu7QLpV8L84P3vFmEiZxL020t2EqIubP7HHHxrSsqS",
stubDevelopmentEvents: true, // [DO NOT TOUCH] Core team only.
label: "telemetry_id",
/*
Key value pairs of events that should be debounced to prevent spamming the logs.
This should be used for events that could be triggered in rapid succession that are not useful to atomically log.
The value is the number of seconds to debounce the event
*/
debounced: {
sent_chat: 1800,
agent_chat_sent: 1800,
agent_chat_started: 1800,
agent_tool_call: 1800,
// Document mgmt events
document_uploaded: 30,
documents_embedded_in_workspace: 30,
link_uploaded: 30,
raw_document_uploaded: 30,
document_parsed: 30,
},
id: async function () {
const result = await SystemSettings.get({ label: this.label });
return result?.value || null;
},
connect: async function () {
const client = this.client();
const distinctId = await this.findOrCreateId();
return { client, distinctId };
},
isDev: function () {
return process.env.NODE_ENV === "development" && this.stubDevelopmentEvents;
},
client: function () {
if (process.env.DISABLE_TELEMETRY === "true" || this.isDev()) return null;
const { PostHog } = require("posthog-node");
return new PostHog(this.pubkey);
},
runtime: function () {
if (process.env.ANYTHING_LLM_RUNTIME === "docker") return "docker";
if (process.env.NODE_ENV === "production") return "production";
return "other";
},
/**
* Checks if the event is on cooldown
* @param {string} event - The event to check
* @returns {boolean} - True if the event is on cooldown, false otherwise
*/
isOnCooldown: function (event) {
// If the event is not debounced, return false
if (!this.debounced[event]) return false;
// If the event is not in the cooldown map, return false
const lastSent = TelemetryCooldown.get(event);
if (!lastSent) return false;
// If the event is in the cooldown map, check if it has expired
const now = Date.now();
const cooldown = this.debounced[event] * 1000;
return now - lastSent < cooldown;
},
/**
* Marks the event as on cooldown - will check if the event is debounced first
* @param {string} event - The event to mark
*/
markOnCooldown: function (event) {
if (!this.debounced[event]) return;
TelemetryCooldown.set(event, Date.now());
},
sendTelemetry: async function (
event,
eventProperties = {},
subUserId = null,
silent = false
) {
try {
const { client, distinctId: systemId } = await this.connect();
if (!client) return;
const distinctId = !!subUserId ? `${systemId}::${subUserId}` : systemId;
const properties = { ...eventProperties, runtime: this.runtime() };
// If the event is on cooldown, return
if (this.isOnCooldown(event)) return;
// Silence some events to keep logs from being too messy in production
// eg: Tool calls from agents spamming the logs.
if (!silent) {
console.log(`\x1b[32m[TELEMETRY SENT]\x1b[0m`, {
event,
distinctId,
properties,
});
}
client.capture({
event,
distinctId,
properties,
});
} catch {
return;
} finally {
// Mark the event as on cooldown if needed
this.markOnCooldown(event);
}
},
flush: async function () {
const client = this.client();
if (!client) return;
await client.shutdownAsync();
},
setUid: async function () {
const newId = v4();
await SystemSettings._updateSettings({ [this.label]: newId });
return newId;
},
findOrCreateId: async function () {
let currentId = await this.id();
if (currentId) return currentId;
currentId = await this.setUid();
return currentId;
},
};
module.exports = { Telemetry };
|