mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-19 20:50:09 +01:00
Enable optional Telemetry integration via posthog (#190)
* Enable optional Telemetry integration via posthog
This commit is contained in:
parent
b557bb9ede
commit
122f29069c
25
README.md
25
README.md
@ -81,7 +81,30 @@ Next, you will need some content to embed. This could be a Youtube Channel, Medi
|
||||
|
||||
[Learn about vector caching](./server/storage/vector-cache/VECTOR_CACHE.md)
|
||||
|
||||
### Contributing
|
||||
## Contributing
|
||||
- create issue
|
||||
- create PR with branch name format of `<issue number>-<short name>`
|
||||
- yee haw let's merge
|
||||
|
||||
## Telemetry
|
||||
AnythingLLM by Mintplex Labs Inc contains a telemetry feature that collects anonymous usage information.
|
||||
|
||||
### Why?
|
||||
We use this information to help us understand how AnythingLLM is used, to help us prioritize work on new features and bug fixes, and to help us improve AnythingLLM's performance and stability.
|
||||
|
||||
### Opting out
|
||||
Set `DISABLE_TELEMETRY` in your server or docker .env settings to "true" to opt out of telemetry.
|
||||
|
||||
```
|
||||
DISABLE_TELEMETRY="true"
|
||||
```
|
||||
|
||||
### What do you explicitly track?
|
||||
We will only track usage details that help us make product and roadmap decisions, specifically:
|
||||
- Version of your installation
|
||||
- When a document is added or removed. No information _about_ the document. Just that the event occurred. This gives us an idea of use.
|
||||
- Type of vector database in use. Let's us know which vector database provider is the most used to prioritize changes when updates arrive for that provider.
|
||||
- Type of LLM in use. Let's us know the most popular choice and prioritize changes when updates arrive for that provider.
|
||||
- Chat is sent. This is the most regular "event" and gives us an idea of the daily-activity of this project across all installations. Again, only the event is sent - we have no information on the nature or content of the chat itself.
|
||||
|
||||
You can verify these claims by finding all locations `Telemetry.sendTelemetry` is called. Additionally these events are written to the output log so you can also see the specific data which was sent - if enabled. No IP or other identifying information is collected. The Telemetry provider is [PostHog](https://posthog.com/) - an open-source telemetry collection service.
|
@ -5,6 +5,7 @@ const { chatWithWorkspace } = require("../utils/chats");
|
||||
const { validatedRequest } = require("../utils/middleware/validatedRequest");
|
||||
const { WorkspaceChats } = require("../models/workspaceChats");
|
||||
const { SystemSettings } = require("../models/systemSettings");
|
||||
const { Telemetry } = require("../models/telemetry");
|
||||
|
||||
function chatEndpoints(app) {
|
||||
if (!app) return;
|
||||
@ -55,6 +56,11 @@ function chatEndpoints(app) {
|
||||
}
|
||||
|
||||
const result = await chatWithWorkspace(workspace, message, mode, user);
|
||||
await Telemetry.sendTelemetry("sent_chat", {
|
||||
multiUserMode: multiUserMode(response),
|
||||
LLMSelection: process.env.LLM_PROVIDER || "openai",
|
||||
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
|
||||
});
|
||||
response.status(200).json({ ...result });
|
||||
} catch (e) {
|
||||
response.status(500).json({
|
||||
|
@ -34,6 +34,7 @@ const {
|
||||
removeCustomLogo,
|
||||
DARK_LOGO_FILENAME,
|
||||
} = require("../utils/files/logo");
|
||||
const { Telemetry } = require("../models/telemetry");
|
||||
|
||||
function systemEndpoints(app) {
|
||||
if (!app) return;
|
||||
@ -325,6 +326,7 @@ function systemEndpoints(app) {
|
||||
});
|
||||
process.env.AUTH_TOKEN = null;
|
||||
process.env.JWT_SECRET = process.env.JWT_SECRET ?? v4(); // Make sure JWT_SECRET is set for JWT issuance.
|
||||
await Telemetry.sendTelemetry("enabled_multi_user_mode");
|
||||
response.status(200).json({ success: !!user, error });
|
||||
} catch (e) {
|
||||
console.log(e.message, e);
|
||||
|
@ -49,4 +49,4 @@ function utilEndpoints(app) {
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { utilEndpoints };
|
||||
module.exports = { utilEndpoints, getGitVersion };
|
||||
|
@ -15,6 +15,7 @@ const {
|
||||
} = require("../utils/files/documentProcessor");
|
||||
const { validatedRequest } = require("../utils/middleware/validatedRequest");
|
||||
const { SystemSettings } = require("../models/systemSettings");
|
||||
const { Telemetry } = require("../models/telemetry");
|
||||
const { handleUploads } = setupMulter();
|
||||
|
||||
function workspaceEndpoints(app) {
|
||||
@ -25,6 +26,11 @@ function workspaceEndpoints(app) {
|
||||
const user = await userFromSession(request, response);
|
||||
const { name = null } = reqBody(request);
|
||||
const { workspace, message } = await Workspace.new(name, user?.id);
|
||||
await Telemetry.sendTelemetry("workspace_created", {
|
||||
multiUserMode: multiUserMode(response),
|
||||
LLMSelection: process.env.LLM_PROVIDER || "openai",
|
||||
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
|
||||
});
|
||||
response.status(200).json({ workspace, message });
|
||||
} catch (e) {
|
||||
console.log(e.message, e);
|
||||
@ -87,6 +93,7 @@ function workspaceEndpoints(app) {
|
||||
console.log(
|
||||
`Document ${originalname} uploaded processed and successfully. It is now available in documents.`
|
||||
);
|
||||
await Telemetry.sendTelemetry("document_uploaded");
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
@ -12,10 +12,11 @@ const { systemEndpoints } = require("./endpoints/system");
|
||||
const { workspaceEndpoints } = require("./endpoints/workspaces");
|
||||
const { chatEndpoints } = require("./endpoints/chat");
|
||||
const { getVectorDbClass } = require("./utils/helpers");
|
||||
const { validateTablePragmas } = require("./utils/database");
|
||||
const { validateTablePragmas, setupTelemetry } = require("./utils/database");
|
||||
const { adminEndpoints } = require("./endpoints/admin");
|
||||
const { inviteEndpoints } = require("./endpoints/invite");
|
||||
const { utilEndpoints } = require("./endpoints/utils");
|
||||
const { Telemetry } = require("./models/telemetry");
|
||||
const app = express();
|
||||
const apiRouter = express.Router();
|
||||
|
||||
@ -86,15 +87,18 @@ app.all("*", function (_, response) {
|
||||
app
|
||||
.listen(process.env.SERVER_PORT || 3001, async () => {
|
||||
await validateTablePragmas();
|
||||
await setupTelemetry();
|
||||
console.log(
|
||||
`Example app listening on port ${process.env.SERVER_PORT || 3001}`
|
||||
);
|
||||
})
|
||||
.on("error", function (err) {
|
||||
process.once("SIGUSR2", function () {
|
||||
Telemetry.flush();
|
||||
process.kill(process.pid, "SIGUSR2");
|
||||
});
|
||||
process.on("SIGINT", function () {
|
||||
Telemetry.flush();
|
||||
process.kill(process.pid, "SIGINT");
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ const { fileData } = require("../utils/files");
|
||||
const { v4: uuidv4 } = require("uuid");
|
||||
const { getVectorDbClass } = require("../utils/helpers");
|
||||
const { checkForMigrations } = require("../utils/database");
|
||||
const { Telemetry } = require("./telemetry");
|
||||
|
||||
const Document = {
|
||||
tablename: "workspace_documents",
|
||||
@ -120,6 +121,10 @@ const Document = {
|
||||
|
||||
stmt.finalize();
|
||||
db.close();
|
||||
await Telemetry.sendTelemetry("documents_embedded_in_workspace", {
|
||||
LLMSelection: process.env.LLM_PROVIDER || "openai",
|
||||
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
|
||||
});
|
||||
return;
|
||||
},
|
||||
removeDocuments: async function (workspace, removals = []) {
|
||||
@ -156,6 +161,10 @@ const Document = {
|
||||
|
||||
stmt.finalize();
|
||||
db.close();
|
||||
await Telemetry.sendTelemetry("documents_removed_in_workspace", {
|
||||
LLMSelection: process.env.LLM_PROVIDER || "openai",
|
||||
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
|
||||
});
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
@ -5,6 +5,7 @@ const SystemSettings = {
|
||||
"limit_user_messages",
|
||||
"message_limit",
|
||||
"logo_filename",
|
||||
"telemetry_id",
|
||||
],
|
||||
privateField: [],
|
||||
tablename: "system_settings",
|
||||
|
65
server/models/telemetry.js
Normal file
65
server/models/telemetry.js
Normal file
@ -0,0 +1,65 @@
|
||||
const { v4 } = require("uuid");
|
||||
const { SystemSettings } = require("./systemSettings");
|
||||
|
||||
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",
|
||||
id: async function () {
|
||||
const result = await SystemSettings.get(`label = '${this.label}'`);
|
||||
if (!!result?.value) return result.value;
|
||||
return result?.value;
|
||||
},
|
||||
connect: async function () {
|
||||
const client = this.client();
|
||||
const distinctId = await this.findOrCreateId();
|
||||
return { client, distinctId };
|
||||
},
|
||||
isDev: function () {
|
||||
if (process.env.NODE_ENV === "development")
|
||||
return this.stubDevelopmentEvents;
|
||||
return false;
|
||||
},
|
||||
client: function () {
|
||||
if (process.env.DISABLE_TELEMETRY === "true" || this.isDev()) return null;
|
||||
const { PostHog } = require("posthog-node");
|
||||
return new PostHog(this.pubkey);
|
||||
},
|
||||
sendTelemetry: async function (event, properties = {}) {
|
||||
try {
|
||||
const { client, distinctId } = await this.connect();
|
||||
if (!client) return;
|
||||
console.log(`\x1b[32m[TELEMETRY SENT]\x1b[0m`, {
|
||||
event,
|
||||
properties,
|
||||
});
|
||||
client.capture({
|
||||
event,
|
||||
distinctId,
|
||||
properties,
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
},
|
||||
flush: async function () {
|
||||
const { client } = this.client();
|
||||
if (!client) return;
|
||||
await client.shutdownAsync();
|
||||
return;
|
||||
},
|
||||
setUid: async function () {
|
||||
const newId = v4();
|
||||
await SystemSettings.updateSettings({ [this.label]: newId });
|
||||
return newId;
|
||||
},
|
||||
findOrCreateId: async function () {
|
||||
const currentId = await this.id();
|
||||
if (!!currentId) return currentId;
|
||||
const newId = await this.setUid();
|
||||
return newId;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = { Telemetry };
|
@ -35,6 +35,7 @@
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"openai": "^3.2.1",
|
||||
"pinecone-client": "^1.1.0",
|
||||
"posthog-node": "^3.1.1",
|
||||
"serve-index": "^1.9.1",
|
||||
"slugify": "^1.6.6",
|
||||
"sqlite": "^4.2.1",
|
||||
|
@ -1,3 +1,6 @@
|
||||
const { getGitVersion } = require("../../endpoints/utils");
|
||||
const { Telemetry } = require("../../models/telemetry");
|
||||
|
||||
function checkColumnTemplate(tablename = null, column = null) {
|
||||
if (!tablename || !column)
|
||||
throw new Error(`Migration Error`, { tablename, column });
|
||||
@ -73,7 +76,37 @@ async function validateTablePragmas(force = false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Telemetry is anonymized and your data is never read. This can be disabled by setting
|
||||
// DISABLE_TELEMETRY=true in the `.env` of however you setup. Telemetry helps us determine use
|
||||
// of how AnythingLLM is used and how to improve this product!
|
||||
// You can see all Telemetry events by ctrl+f `Telemetry.sendEvent` calls to verify this claim.
|
||||
async function setupTelemetry() {
|
||||
if (process.env.DISABLE_TELEMETRY === "true") {
|
||||
console.log(
|
||||
`\x1b[31m[TELEMETRY DISABLED]\x1b[0m Telemetry is marked as disabled - no events will send. Telemetry helps Mintplex Labs Inc improve AnythingLLM.`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Telemetry.isDev()) {
|
||||
console.log(
|
||||
`\x1b[33m[TELEMETRY STUBBED]\x1b[0m Anonymous Telemetry stubbed in development.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`\x1b[32m[TELEMETRY ENABLED]\x1b[0m Anonymous Telemetry enabled. Telemetry helps Mintplex Labs Inc improve AnythingLLM.`
|
||||
);
|
||||
await Telemetry.findOrCreateId();
|
||||
await Telemetry.sendTelemetry("server_boot", {
|
||||
commit: getGitVersion(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkForMigrations,
|
||||
validateTablePragmas,
|
||||
setupTelemetry,
|
||||
};
|
||||
|
@ -390,6 +390,14 @@ axios@^0.26.0:
|
||||
dependencies:
|
||||
follow-redirects "^1.14.8"
|
||||
|
||||
axios@^0.27.0:
|
||||
version "0.27.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
|
||||
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.9"
|
||||
form-data "^4.0.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
@ -991,7 +999,7 @@ flatbuffers@23.3.3:
|
||||
resolved "https://registry.yarnpkg.com/flatbuffers/-/flatbuffers-23.3.3.tgz#23654ba7a98d4b866a977ae668fe4f8969f34a66"
|
||||
integrity sha512-jmreOaAT1t55keaf+Z259Tvh8tR/Srry9K8dgCgvizhKSEr6gLGgaOJI2WFL5fkOpGOGRZwxUrlFn0GCmXUy6g==
|
||||
|
||||
follow-redirects@^1.14.8:
|
||||
follow-redirects@^1.14.8, follow-redirects@^1.14.9:
|
||||
version "1.15.2"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||
@ -2026,6 +2034,14 @@ pinecone-client@^1.1.0:
|
||||
dependencies:
|
||||
ky "^0.33.1"
|
||||
|
||||
posthog-node@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-3.1.1.tgz#f92c44a871552c9bfb98bf4cc8fd326d36af6cbd"
|
||||
integrity sha512-OUSYcnLHbzvY/dxNsbUGoYuTZz5XNx48BkfiCkOIJZMFvot5VPQ0KWEjX+kzYxEwHeXbjW9plqsOVcYCYfidgg==
|
||||
dependencies:
|
||||
axios "^0.27.0"
|
||||
rusha "^0.8.14"
|
||||
|
||||
prettier@^2.4.1:
|
||||
version "2.8.8"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
|
||||
@ -2172,6 +2188,11 @@ rimraf@^3.0.2:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rusha@^0.8.14:
|
||||
version "0.8.14"
|
||||
resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.14.tgz#a977d0de9428406138b7bb90d3de5dcd024e2f68"
|
||||
integrity sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==
|
||||
|
||||
safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
|
Loading…
Reference in New Issue
Block a user