Skip to content

Commit

Permalink
add simulation logger
Browse files Browse the repository at this point in the history
  • Loading branch information
jbolda committed Aug 13, 2024
1 parent 5e0c9cc commit ab1c616
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changes/foundation-sim-logger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@simulacrum/foundation-simulator": minor:feat
---

All routes now add a log to the simulation state on every visit. This assists in tracking hits on each simulation route.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/foundation/example/extensiveServer/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const inputSelectors = ({
};

export const extendStore = {
logs: false,
actions: inputActions,
selectors: inputSelectors,
schema: inputSchema,
Expand Down
1 change: 1 addition & 0 deletions packages/foundation/example/singleFileServer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const simulation = createFoundationSimulationServer({
},
],
extendStore: {
logs: false,
actions: ({ thunks, schema }) => {
// TODO attempt to remove this type as a requirement
let upsertTest = thunks.create<AnyState>(
Expand Down
1 change: 1 addition & 0 deletions packages/foundation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"dependencies": {
"ajv-formats": "^3.0.1",
"cors": "^2.8.5",
"express": "^4.19.2",
"fdir": "^6.2.0",
"openapi-backend": "^5.10.6",
Expand Down
20 changes: 19 additions & 1 deletion packages/foundation/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import express from "express";
import cors from "cors";
import type {
Request as ExpressRequest,
Response as ExpressResponse,
Expand Down Expand Up @@ -96,10 +97,23 @@ export function createFoundationSimulationServer<
}) {
return () => {
let app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
let simulationStore = createSimulationStore(extendStore);

app.use((req, res, next) => {
simulationStore.store.dispatch(
simulationStore.actions.simulationLog({
method: req.method,
url: req.url,
query: req.query,
body: req.body,
})
);
next();
});

if (serveJsonFiles) {
const jsonFiles = new fdir()
.filter((path, _isDirectory) => path.endsWith(".json"))
Expand Down Expand Up @@ -237,10 +251,13 @@ export function createFoundationSimulationServer<
let routes = simulationStore.schema.simulationRoutes.selectTableAsList(
simulationStore.store.getState()
);
let logs = simulationStore.schema.simulationLogs.selectTableAsList(
simulationStore.store.getState()
);
if (routes.length === 0) {
res.sendStatus(404);
} else {
res.status(200).send(generateRoutesHTML(routes));
res.status(200).send(generateRoutesHTML(routes, logs));
}
});
app.post("/", (req, res) => {
Expand Down Expand Up @@ -272,6 +289,7 @@ export function createFoundationSimulationServer<

return {
server,
simulationStore,
ensureClose: async () => {
await new Promise<void>((resolve) => {
server.once("close", resolve);
Expand Down
14 changes: 11 additions & 3 deletions packages/foundation/src/routeTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SimulationRoute } from "./store/schema";
import type { SimulationLog, SimulationRoute } from "./store/schema";

const responseSubmit = (routeId: string, response: number) => /* HTML */ `<form
action=""
Expand All @@ -8,7 +8,10 @@ const responseSubmit = (routeId: string, response: number) => /* HTML */ `<form
</form>`;
const routeToId = (route: SimulationRoute) => `${route.method}:${route.url}`;

export const generateRoutesHTML = (routes: SimulationRoute[]) => {
export const generateRoutesHTML = (
routes: SimulationRoute[],
logs: SimulationLog[]
) => {
return /* HTML */ `<!DOCTYPE html>
<html>
<head>
Expand Down Expand Up @@ -61,7 +64,8 @@ export const generateRoutesHTML = (routes: SimulationRoute[]) => {
</head>
<body>
<main class="my-12">
<h1>Simulation Routes</h1>
<h1>Simulation</h1>
<h2>Routes</h2>
<div class="routes">
<span>Method</span>
<span>URL</span>
Expand All @@ -85,6 +89,10 @@ export const generateRoutesHTML = (routes: SimulationRoute[]) => {
)
.join("\n")}
</div>
<h2>Logs</h2>
<div class="simulation-logs">
${logs.map((log) => `<div>${log.message}</div>`).join("")}
</div>
</main>
</body>
</html>`;
Expand Down
21 changes: 21 additions & 0 deletions packages/foundation/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ export function createSimulationStore<
yield* next();
}
);
let simulationLog = thunks.create<{
method: string;
url: string;
query: Record<string, any>;
body: any;
}>("simulationLog", function* (ctx, next) {
const { method, url, query, body } = ctx.payload;
const timestamp = Date.now();
yield* schema.update(
schema.simulationLogs.add({
[timestamp]: {
timestamp,
level: "info",
message: `${method} ${url}`,
meta: { method, url, query, body },
},
})
);
yield* next();
});

let additionalTasks = [thunks.bootup];

Expand All @@ -86,6 +106,7 @@ export function createSimulationStore<

let inputedActions = inputActions({ thunks, store, schema });
let actions = {
simulationLog,
batchUpdater,
...inputedActions,
};
Expand Down
8 changes: 8 additions & 0 deletions packages/foundation/src/store/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ export type ExtendSimulationSchemaInput<T> = ({
slice,
}: ExtendSimulationSchema) => T;

export interface SimulationLog {
timestamp: number;
level: "debug" | "info" | "error";
message: string;
meta?: Record<string, any>;
}

export interface SimulationRoute {
type: "JSON" | "OpenAPI" | "Explicit";
url: string;
Expand All @@ -25,6 +32,7 @@ export function generateSchemaWithInputSlices<ExtendedSimulationSchema>(
let schemaAndInitialState = createSchema({
cache: immerSlice.table({ empty: {} }),
loaders: immerSlice.loaders(),
simulationLogs: immerSlice.table<SimulationLog>(),
simulationRoutes: immerSlice.table<SimulationRoute>({
empty: {
type: "Explicit",
Expand Down

0 comments on commit ab1c616

Please sign in to comment.