WIP event logging - new table for events and new settings view for viewing

This commit is contained in:
shatfield4 2024-02-01 18:19:40 -08:00
parent 9d410496c0
commit e95d547be6
8 changed files with 160 additions and 0 deletions

View File

@ -20,6 +20,7 @@ const AdminUsers = lazy(() => import("@/pages/Admin/Users"));
const AdminInvites = lazy(() => import("@/pages/Admin/Invitations"));
const AdminWorkspaces = lazy(() => import("@/pages/Admin/Workspaces"));
const AdminSystem = lazy(() => import("@/pages/Admin/System"));
const AdminLogs = lazy(() => import("@/pages/Admin/Logs"));
const GeneralChats = lazy(() => import("@/pages/GeneralSettings/Chats"));
const GeneralAppearance = lazy(
() => import("@/pages/GeneralSettings/Appearance")
@ -70,6 +71,10 @@ export default function App() {
path="/settings/vector-database"
element={<AdminRoute Component={GeneralVectorDatabase} />}
/>
<Route
path="/settings/logs"
element={<AdminRoute Component={AdminLogs} />}
/>
{/* Manager */}
<Route
path="/settings/security"

View File

@ -19,6 +19,7 @@ import {
List,
FileCode,
Plugs,
Notepad,
} from "@phosphor-icons/react";
import useUser from "@/hooks/useUser";
import { USER_BACKGROUND_COLOR } from "@/utils/constants";
@ -154,6 +155,14 @@ export default function SettingsSidebar() {
flex={true}
allowedRole={["admin", "manager"]}
/>
<Option
href={paths.settings.logs()}
btnText="Logs"
icon={<Notepad className="h-5 w-5 flex-shrink-0" />}
user={user}
flex={true}
allowedRole={["admin", "manager"]}
/>
</div>
</div>
<div>

View File

@ -93,6 +93,9 @@ export default {
apiKeys: () => {
return "/settings/api-keys";
},
logs: () => {
return "/settings/logs";
},
dataConnectors: {
list: () => {
return "/settings/data-connectors";

View File

@ -14,6 +14,7 @@ const {
ROLES,
flexUserRoleValid,
} = require("../utils/middleware/multiUserProtected");
const { EventLogs } = require("../models/eventLogs");
function chatEndpoints(app) {
if (!app) return;
@ -98,6 +99,16 @@ function chatEndpoints(app) {
Embedder: process.env.EMBEDDING_ENGINE || "inherit",
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
});
await EventLogs.logEvent({
event: "sent_chat",
userId: user?.id || null,
metadata: {
multiUserMode: multiUserMode(response),
LLMSelection: process.env.LLM_PROVIDER || "openai",
Embedder: process.env.EMBEDDING_ENGINE || "inherit",
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
},
});
response.end();
} catch (e) {
console.error(e);

View File

@ -48,6 +48,7 @@ const {
prepareWorkspaceChatsForExport,
exportChatsAsType,
} = require("../utils/helpers/chat/convertTo");
const { EventLogs } = require("../models/eventLogs");
function systemEndpoints(app) {
if (!app) return;
@ -148,6 +149,12 @@ function systemEndpoints(app) {
{ multiUserMode: false },
existingUser?.id
);
await EventLogs.logEvent({
event: "login_event",
userId: existingUser?.id || null,
metadata: {},
});
response.status(200).json({
valid: true,
user: existingUser,

View File

@ -0,0 +1,96 @@
const prisma = require("../utils/prisma");
const EventLogs = {
logEvent: async function ({
event,
description = null,
metadata = null,
userId = null,
ipAddress = null,
}) {
try {
const eventLog = await prisma.event_logs.create({
data: {
event,
description,
metadata: metadata ? JSON.stringify(metadata) : null,
userId,
occurredAt: new Date(),
ipAddress,
},
});
return { eventLog, message: null };
} catch (error) {
console.error(error.message);
return { eventLog: null, message: error.message };
}
},
getByEvent: async function (event, limit = null, orderBy = null) {
try {
const logs = await prisma.event_logs.findMany({
where: { event },
...(limit !== null ? { take: limit } : {}),
...(orderBy !== null
? { orderBy }
: { orderBy: { occurredAt: "desc" } }),
});
return logs;
} catch (error) {
console.error(error.message);
return [];
}
},
getByUserId: async function (userId, limit = null, orderBy = null) {
try {
const logs = await prisma.event_logs.findMany({
where: { userId },
...(limit !== null ? { take: limit } : {}),
...(orderBy !== null
? { orderBy }
: { orderBy: { occurredAt: "desc" } }),
});
return logs;
} catch (error) {
console.error(error.message);
return [];
}
},
where: async function (
clause = {},
limit = null,
orderBy = null,
offset = null
) {
try {
const logs = await prisma.event_logs.findMany({
where: clause,
...(limit !== null ? { take: limit } : {}),
...(offset !== null ? { skip: offset } : {}),
...(orderBy !== null
? { orderBy }
: { orderBy: { occurredAt: "desc" } }),
});
return logs;
} catch (error) {
console.error(error.message);
return [];
}
},
count: async function (clause = {}) {
try {
const count = await prisma.event_logs.count({
where: clause,
});
return count;
} catch (error) {
console.error(error.message);
return 0;
}
},
};
module.exports = { EventLogs };

View File

@ -0,0 +1,16 @@
-- CreateTable
CREATE TABLE "event_logs" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"event" TEXT NOT NULL,
"description" TEXT,
"metadata" TEXT,
"userId" INTEGER,
"occurredAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"ipAddress" TEXT
);
-- CreateIndex
CREATE INDEX "event_logs_userId_idx" ON "event_logs"("userId");
-- CreateIndex
CREATE INDEX "event_logs_event_idx" ON "event_logs"("event");

View File

@ -131,3 +131,16 @@ model cache_data {
createdAt DateTime @default(now())
lastUpdatedAt DateTime @default(now())
}
model event_logs {
id Int @id @default(autoincrement())
event String
description String?
metadata String?
userId Int?
occurredAt DateTime @default(now())
ipAddress String?
@@index([userId])
@@index([event])
}