-
Notifications
You must be signed in to change notification settings - Fork 0
feat: API monitoring #49
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
base: main
Are you sure you want to change the base?
Conversation
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.
Pull request overview
This PR adds API monitoring capabilities to the template API service by integrating Prometheus metrics collection via fastify-metrics and optional Loki logging via pino-loki. The metrics endpoint can be optionally protected with a bearer token for security.
Changes:
- Added fastify-metrics and pino-loki dependencies for monitoring and logging
- Implemented configurable Loki transport for centralized logging
- Created /metrics endpoint with optional authentication via PROMETHEUS_KEY
- Updated test helper to support passing custom options for testing different configurations
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Added dependencies for fastify-metrics, pino-loki, prom-client, and related packages |
| package.json | Added fastify-metrics and pino-loki to dependencies |
| src/app.ts | Implemented Loki transport configuration, metrics endpoint with optional authentication |
| test/helper.ts | Modified build function to accept optional AppOptions for flexible testing |
| test/routes/metrics.test.ts | Added comprehensive tests for metrics endpoint with and without authentication |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (existingLogger && typeof existingLogger === "object") { | ||
| const loggerOptions = existingLogger as { transport?: unknown }; | ||
| const existingTransport = loggerOptions.transport; | ||
|
|
||
| let mergedTransport: unknown; | ||
| if (Array.isArray(existingTransport)) { | ||
| mergedTransport = [...existingTransport, lokiTransport]; | ||
| } else if (existingTransport) { | ||
| mergedTransport = [existingTransport, lokiTransport]; | ||
| } else { | ||
| mergedTransport = lokiTransport; | ||
| } | ||
|
|
||
| options.logger = { | ||
| ...(existingLogger as object), | ||
| transport: mergedTransport, | ||
| } as Exclude<FastifyServerOptions["logger"], boolean | undefined>; | ||
| } else { | ||
| options.logger = { | ||
| level: "info", | ||
| transport: lokiTransport, | ||
| }; | ||
| } |
Copilot
AI
Jan 20, 2026
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.
The Loki transport configuration modifies the options object at module level before the app is created. If the logger option is a boolean (true/false) rather than an object, the code in the else block (lines 111-114) will override it, potentially causing unexpected behavior. The condition on line 93 should also check if existingLogger is not a boolean value to properly handle all logger configuration types.
| if (options.lokiHost) { | ||
| const lokiTransport = { | ||
| target: "pino-loki", | ||
| options: { | ||
| batching: true, | ||
| interval: 5, // Logs are sent every 5 seconds, default. | ||
| host: options.lokiHost, | ||
| labels: { application: packageJson.name }, | ||
| }, | ||
| }; | ||
|
|
||
| const existingLogger = options.logger; | ||
|
|
||
| if (existingLogger && typeof existingLogger === "object") { | ||
| const loggerOptions = existingLogger as { transport?: unknown }; | ||
| const existingTransport = loggerOptions.transport; | ||
|
|
||
| let mergedTransport: unknown; | ||
| if (Array.isArray(existingTransport)) { | ||
| mergedTransport = [...existingTransport, lokiTransport]; | ||
| } else if (existingTransport) { | ||
| mergedTransport = [existingTransport, lokiTransport]; | ||
| } else { | ||
| mergedTransport = lokiTransport; | ||
| } | ||
|
|
||
| options.logger = { | ||
| ...(existingLogger as object), | ||
| transport: mergedTransport, | ||
| } as Exclude<FastifyServerOptions["logger"], boolean | undefined>; | ||
| } else { | ||
| options.logger = { | ||
| level: "info", | ||
| transport: lokiTransport, | ||
| }; | ||
| } | ||
| } |
Copilot
AI
Jan 20, 2026
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.
The Loki transport configuration logic (lines 80-116) lacks test coverage. Since the repository uses comprehensive automated testing for TypeScript code, consider adding tests to verify the logger configuration is correctly merged when lokiHost is provided, especially for edge cases like when logger is a boolean, an object with existing transports (single or array), or undefined.
How this monitoring system will work is that each API service will expose a fastify-metrics endpoint at /metrics, which requires a prometheus key to access.
this is a Prometheus scrapable endpoint for our monitoring platform.
Furthermore, if provided, it will fastify will log automatically to a Loki logging server using pino-loki.
The rest of the setup for monitoring will be done on the usthing server.