workers-loki-logger
Version:
A Logger for the Cloudflare workers environment that sends the logs to grafana loki
193 lines (145 loc) ⢠4.76 kB
Markdown
<!--suppress ALL -->
<h1 align="center">Welcome to Workers Loki Logger š</h1>
[](https://github.com/SirCremefresh/workers-loki-logger/actions/workflows/test.js.yml)

> A Logger for the Cloudflare workers environment that sends the logs to grafana loki
```sh
npm install workers-loki-logger
```
When creating a logger and writing to it all logs are first stored in memory.
It is sent to loki when the flush method is called.
It is recommended to use a wrapper function for the logger to ensure that the logs are flushed to loki.
[](
- Send logs to loki
- Format exceptions as string
- MDC to add additional information to the logs
> Creates a new logger
```typescript
import {Logger} from 'workers-loki-logger';
new Logger({
cloudflareContext: context, // Cloudflare context if this option is set it will use the waitUntil function on flush
lokiSecret: 'some-secret', // Secret for loki authentication
lokiUrl: 'https://logs-prod-eu-west-0.grafana.net', // Url to loki
stream: { // Stream options for loki
worker: 'esm-worker-simple',
environment: 'development',
},
mdc: { // If this option is set it will be used as the initial value for the MDC
requestPath: '/some/path',
}
});
```
> Write log
```typescript
import {Logger} from 'workers-loki-logger';
declare const logger: Logger;
logger.info('message');
logger.warn('message');
logger.warn('message', new Error('some error'));
logger.error('message');
logger.error('message', new Error('some error'));
logger.fatal('message');
logger.fatal('message', new Error('some error'));
```
> Change MDC
```typescript
import {Logger} from 'workers-loki-logger';
declare const logger: Logger;
logger.mdcSet('key', 'value');
logger.mdcGet('key');
logger.mdcDelete('key');
```
> Write logs to loki
```typescript
import {Logger} from 'workers-loki-logger';
declare const logger: Logger;
await logger.flush();
```
```typescript
import {Logger} from 'workers-loki-logger';
function getLogger(context: ExecutionContext, lokiSecret: string) {
return new Logger({
cloudflareContext: context,
lokiSecret,
lokiUrl: 'https://logs-prod-eu-west-0.grafana.net',
stream: {
worker: 'esm-worker-simple',
environment: 'development',
}
});
}
type Environment = {
LOKI_SECRET: string
}
// This function could be moved to a separate file and imported by multiple workers
function onFetch(handler: (request: Request, environment: Environment, context: ExecutionContext, logger: Logger) => Promise<Response>) {
return async (request: Request, environment: Environment, context: ExecutionContext) => {
const logger = getLogger(context, environment.LOKI_SECRET);
logger.mdcSet('requestUrl', request.url);
let response;
try {
response = await handler(request, environment, context, logger);
} catch (error) {
logger.error('Caught error', error);
response = new Response('Internal Server Error', {status: 500});
} finally {
await logger.flush();
}
return response;
};
}
export default {
fetch: onFetch(async (request, environment, context, logger) => {
logger.info('Request received' + request.url);
return await fetch(request);
})
};
```
```typescript
import {Logger} from 'workers-loki-logger';
function getLogger(context: ExecutionContext, lokiSecret: string) {
return new Logger({
cloudflareContext: context,
lokiSecret,
lokiUrl: 'https://logs-prod-eu-west-0.grafana.net',
stream: {
worker: 'esm-worker-simple',
environment: 'development',
}
});
}
export default {
async fetch(request: Request, environment: { LOKI_SECRET: string }, context: ExecutionContext) {
const logger = getLogger(context, environment.LOKI_SECRET);
logger.mdcSet('requestUrl', request.url);
logger.info('Request received' + request.url);
let response;
try {
response = await fetch(request);
} catch (error) {
logger.error('Caught error', error);
response = new Response('Internal Server Error', {status: 500});
} finally {
await logger.flush();
}
return response;
}
};
```
```sh
npm test
```
š¤ **Donato Wolfisberg (donato@wolfibserg.dev) [@SirCremefresh](https://github.com/SirCremefresh)**