Skip to content

Commit 85a4cca

Browse files
authored
feat: add loki functionality to transport logs (#1479)
* Updates the config from env files to include metrics options * updates README * update loki transport * update readme * fix port number on metrics app * update query params metrics * fix import sidecarConfig * fix readme * fix .env and readme
1 parent 1ca7f9b commit 85a4cca

File tree

13 files changed

+437
-45
lines changed

13 files changed

+437
-45
lines changed

.env.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
# For more information on how to use .env files and environment variables
44
# consult the Configuration section in the README.
55

6-
SAS_SUBSTRATE_URL=ws://127.0.0.1:9944
6+
SAS_SUBSTRATE_URL=ws://127.0.0.1:9944

README.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ For more information on our configuration manager visit its readme [here](https:
170170
- `SAS_SUBSTRATE_URL`: URL to which the RPC proxy will attempt to connect to, defaults to
171171
`ws://127.0.0.1:9944`. Accepts both a websocket, and http URL.
172172

173+
### Metrics Server
174+
175+
- `SAS_METRICS_ENABLED`: Boolean to enable the metrics server instance with Prometheus (server metrics) and Loki (logging) connections. Defaults to false.
176+
- `SAS_METRICS_PROM_HOST`: The host of the prometheus server used to listen to metrics emitted, defaults to `127.0.0.1`.
177+
- `SAS_METRICS_PROM_PORT`: The port of the prometheus server, defaults to `9100`.
178+
- `SAS_METRICS_LOKI_HOST`: The host of the loki server used to pull the logs, defaults to `127.0.0.1`.
179+
- `SAS_METRICS_LOKI_PORT`: The port of the loki server, defaults to `3100`
180+
173181
#### Custom substrate types
174182

175183
Some chains require custom type definitions in order for Sidecar to know how to decode the data
@@ -239,23 +247,10 @@ file you can `symlink` it with `.env.test`. For example you could run
239247
commands `ln` and `unlink` for more info.)
240248

241249
### Prometheus server
242-
Prometheus metrics can be enabled by running sidecar with the following flag :
243-
244-
```bash
245-
yarn start --prometheus
246-
```
247-
248-
You can also define a custom port by running :
249-
250-
```bash
251-
yarn start --prometheus --prometheus-port=<YOUR_CUSTOM_PORT>
252-
```
253250

254-
You can also expand the metrics tracking capabilities to include query params by running:
251+
Prometheus metrics can be enabled by running sidecar with the following env configuration: `SAS_METRICS_ENABLED`=true
255252

256-
```bash
257-
yarn start --prometheus --prometheus-queryparams
258-
```
253+
You can also expand the metrics tracking capabilities to include query params by adding to the env configuration: `SAS_METRICS_INCLUDE_QUERYPARAMS`=true
259254

260255
The metrics endpoint can then be accessed :
261256
- on the default port : `http://127.0.0.1:9100/metrics` or
@@ -279,7 +274,17 @@ The blocks controller also includes the following route-specific metrics:
279274
- `sas_extrinsics_per_block`: type histogram and tracks the returned extrinsics per block
280275
- `sas_seconds_per_block`: type histogram and tracks the request time per block
281276

282-
The metrics registry is injected in the Response object when the `-prometheus` flag is selected, allowing to extend the controller based metrics to any given controller from within the controller functions.
277+
The metrics registry is injected in the Response object when the `SAS_METRICS_ENABLED` flag is set to `true` in the `.env` file, allowing to extend the controller based metrics to any given controller from within the controller functions.
278+
279+
To successfully run and access the metrics and logs in Grafana (for example) the following are required:
280+
281+
- prometheus server (info [here](https://prometheus.io/docs/prometheus/latest/getting_started/))
282+
- loki server and promtail (info [here](https://grafana.com/docs/loki/latest/setup/install/))
283+
284+
For mac users using homebrew:
285+
```bash
286+
brew install prometheus loki promtail
287+
```
283288

284289
## Debugging fee and staking payout calculations
285290

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
"lru-cache": "^10.4.3",
6363
"prom-client": "^15.1.3",
6464
"rxjs": "^7.8.1",
65-
"winston": "^3.14.1"
65+
"winston": "^3.14.1",
66+
"winston-loki": "^6.1.2"
6667
},
6768
"devDependencies": {
6869
"@substrate/dev": "^0.7.1",

src/SidecarConfig.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
1+
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
22
// This file is part of Substrate API Sidecar.
33
//
44
// Substrate API Sidecar is free software: you can redistribute it and/or modify
@@ -72,6 +72,14 @@ export class SidecarConfig {
7272
WRITE_MAX_FILE_SIZE: config.Get(MODULES.LOG, CONFIG.WRITE_MAX_FILE_SIZE) as number,
7373
WRITE_MAX_FILES: config.Get(MODULES.LOG, CONFIG.WRITE_MAX_FILES) as number,
7474
},
75+
METRICS: {
76+
ENABLED: config.Get(MODULES.METRICS, CONFIG.ENABLED) as boolean,
77+
PROM_HOST: config.Get(MODULES.METRICS, CONFIG.PROM_HOST) as string,
78+
PROM_PORT: config.Get(MODULES.METRICS, CONFIG.PROM_PORT) as number,
79+
LOKI_HOST: config.Get(MODULES.METRICS, CONFIG.LOKI_HOST) as string,
80+
LOKI_PORT: config.Get(MODULES.METRICS, CONFIG.LOKI_PORT) as number,
81+
INCLUDE_QUERYPARAMS: config.Get(MODULES.METRICS, CONFIG.INCLUDE_QUERYPARAMS) as boolean,
82+
},
7583
};
7684

7785
return this._config;

src/Specs.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
1+
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
22
// This file is part of Substrate API Sidecar.
33
//
44
// Substrate API Sidecar is free software: you can redistribute it and/or modify
@@ -32,6 +32,7 @@ export class Specs {
3232
this.appendLogSpecs();
3333
this.appendSubstrateSpecs();
3434
this.appendExpressSpecs();
35+
this.appendMetricsSpecs();
3536

3637
return this._specs;
3738
}
@@ -242,4 +243,60 @@ export class Specs {
242243
}),
243244
);
244245
}
246+
247+
private static appendMetricsSpecs() {
248+
if (!this._specs) {
249+
throw APPEND_SPEC_ERROR;
250+
}
251+
252+
this._specs.appendSpec(
253+
MODULES.METRICS,
254+
this._specs.getSpec(CONFIG.ENABLED, 'Whether or not to enable metrics', {
255+
default: 'false',
256+
type: 'boolean',
257+
regexp: /^true|false$/,
258+
}),
259+
);
260+
261+
this._specs.appendSpec(
262+
MODULES.METRICS,
263+
this._specs.getSpec(CONFIG.PROM_HOST, 'Prometheus host', {
264+
default: '127.0.0.1',
265+
type: 'string',
266+
}),
267+
);
268+
269+
this._specs.appendSpec(
270+
MODULES.METRICS,
271+
this._specs.getSpec(CONFIG.PROM_PORT, 'Prometheus port', {
272+
default: 9100,
273+
type: 'number',
274+
regexp: /^\d{2,6}$/,
275+
}),
276+
);
277+
278+
this._specs.appendSpec(
279+
MODULES.METRICS,
280+
this._specs.getSpec(CONFIG.LOKI_HOST, 'Loki host', {
281+
default: '127.0.0.1',
282+
type: 'string',
283+
}),
284+
);
285+
this._specs.appendSpec(
286+
MODULES.METRICS,
287+
this._specs.getSpec(CONFIG.LOKI_PORT, 'Loki port', {
288+
default: 3100,
289+
type: 'number',
290+
}),
291+
);
292+
293+
this._specs.appendSpec(
294+
MODULES.METRICS,
295+
this._specs.getSpec(CONFIG.INCLUDE_QUERYPARAMS, 'Include query params in the labels of the metrics', {
296+
default: 'false',
297+
type: 'boolean',
298+
regexp: /^true|false$/,
299+
}),
300+
);
301+
}
245302
}

src/logging/Log.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import { createLogger, Logger } from 'winston';
1818
import { ConsoleTransportInstance, FileTransportInstance } from 'winston/lib/winston/transports';
19+
import LokiTransport from 'winston-loki';
1920

2021
import { SidecarConfig } from '../SidecarConfig';
2122
import { consoleTransport, fileTransport } from './transports';
@@ -24,7 +25,7 @@ import { consoleTransport, fileTransport } from './transports';
2425
* Access a singleton winston.Logger that will be intialized on first use.
2526
*/
2627
export class Log {
27-
private static _transports: (ConsoleTransportInstance | FileTransportInstance)[] | undefined;
28+
private static _transports: (ConsoleTransportInstance | FileTransportInstance | LokiTransport)[] | undefined;
2829
private static _logger: Logger | undefined;
2930
private static create(): Logger {
3031
if (this._logger) {
@@ -40,6 +41,16 @@ export class Log {
4041
this._transports.push(fileTransport('logs.log'));
4142
}
4243

44+
if (SidecarConfig.config.METRICS.ENABLED) {
45+
this._transports.push(
46+
new LokiTransport({
47+
host: `http://${SidecarConfig.config.METRICS.LOKI_HOST}:${SidecarConfig.config.METRICS.LOKI_PORT}`,
48+
useWinstonMetaAsLabels: true,
49+
json: true,
50+
}),
51+
);
52+
}
53+
4354
this._logger = createLogger({
4455
transports: this._transports,
4556
exitOnError: false,

src/main.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ async function main() {
6666
startUpPrompt(config.SUBSTRATE.URL, chainName.toString(), implName.toString());
6767

6868
const preMiddlewares = [json(), middleware.httpLoggerCreate(logger)];
69-
if (args.prometheus) {
69+
70+
if (config.METRICS.ENABLED) {
7071
// Create Metrics App
7172
const metricsApp = new MetricsApp({
72-
port: 9100,
73-
host: config.EXPRESS.HOST,
73+
port: config.METRICS.PROM_PORT,
74+
host: config.METRICS.PROM_HOST,
7475
});
7576

7677
// Generate metrics middleware

src/metrics/Metrics.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Application, Request, Response } from 'express';
33
import client from 'prom-client';
44

55
import { Log } from '../logging/Log';
6-
import { parseArgs } from '../parseArgs';
6+
import { SidecarConfig } from '../SidecarConfig';
77
import { IMetric, MetricType } from '../types/metrics';
88
import { config } from '.';
99

@@ -35,11 +35,9 @@ export default class Metrics_App {
3535
/**
3636
* @param appConfig configuration for app.
3737
*/
38-
constructor({ host }: IAppConfiguration) {
39-
const args = parseArgs();
40-
41-
this.includeQueryParams = !!args.prometheus_queryparams;
42-
this.port = Number(args.prometheus_port);
38+
constructor({ host, port }: IAppConfiguration) {
39+
this.includeQueryParams = SidecarConfig.config.METRICS.INCLUDE_QUERYPARAMS;
40+
this.port = port;
4341
this.app = express();
4442
this.host = host;
4543
this.registry = new client.Registry();

src/parseArgs.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,6 @@ export const parseArgs = (): Namespace => {
2323
action: 'store_true',
2424
help: 'print substrate-api-sidecar version',
2525
});
26-
parser.add_argument('-p', '--prometheus', {
27-
action: 'store_true',
28-
help: 'enable the prometheus metrics endpoint',
29-
});
30-
parser.add_argument('-pp', '--prometheus-port', {
31-
type: 'int',
32-
default: 9100,
33-
help: 'specify the port number on which the prometheus metrics are exposed [default: 9100]',
34-
});
35-
parser.add_argument('-pq', '--prometheus-queryparams', {
36-
action: 'store_true',
37-
help: 'enambles query parameters in the prometheus metrics',
38-
});
3926

4027
return parser.parse_args() as Namespace;
4128
};

src/types/sidecar-config/CONFIG.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,10 @@ export enum CONFIG {
3434
WRITE_PATH = 'WRITE_PATH',
3535
WRITE_MAX_FILE_SIZE = 'WRITE_MAX_FILE_SIZE',
3636
WRITE_MAX_FILES = 'WRITE_MAX_FILES',
37+
ENABLED = 'ENABLED',
38+
LOKI_HOST = 'LOKI_HOST',
39+
PROM_PORT = 'PROM_PORT',
40+
PROM_HOST = 'PROM_HOST',
41+
LOKI_PORT = 'LOKI_PORT',
42+
INCLUDE_QUERYPARAMS = 'INCLUDE_QUERYPARAMS',
3743
}

0 commit comments

Comments
 (0)