@breautek/storm 9.6.4 → 9.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +453 -880
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/main.js +3 -3
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/Application.html +23 -18
- package/docs/classes/ConfigLoader.html +3 -3
- package/docs/classes/Database.html +2 -2
- package/docs/classes/DatabaseCastObject.html +2 -2
- package/docs/classes/DatabaseConnection.html +21 -21
- package/docs/classes/DatabaseQueryError.html +6 -6
- package/docs/classes/DeadLockError.html +6 -6
- package/docs/classes/DiskSpaceError.html +5 -5
- package/docs/classes/DropTemporaryTableQuery.html +7 -7
- package/docs/classes/DuplicateEntryError.html +5 -5
- package/docs/classes/EntityNotFoundError.html +5 -5
- package/docs/classes/ExpiredTokenError.html +5 -5
- package/docs/classes/ForbiddenError.html +5 -5
- package/docs/classes/GetMySQLVersion.html +7 -7
- package/docs/classes/Handler.html +2 -2
- package/docs/classes/IllegalStateError.html +5 -5
- package/docs/classes/InternalError.html +5 -5
- package/docs/classes/InvalidCredentialsError.html +5 -5
- package/docs/classes/InvalidValueError.html +5 -5
- package/docs/classes/LineString.html +2 -2
- package/docs/classes/LockWaitTimeoutError.html +6 -6
- package/docs/classes/ManagedDatabaseConnection.html +5 -5
- package/docs/classes/MetricStore.html +6 -6
- package/docs/classes/Middleware.html +2 -2
- package/docs/classes/MissingConfigError.html +5 -5
- package/docs/classes/MissingParameterError.html +5 -5
- package/docs/classes/MySQLConnection.html +25 -25
- package/docs/classes/MySQLDatabase.html +2 -2
- package/docs/classes/NotImplementedError.html +5 -5
- package/docs/classes/Point.html +2 -2
- package/docs/classes/Polygon.html +2 -2
- package/docs/classes/Query.html +7 -7
- package/docs/classes/RawError.html +5 -5
- package/docs/classes/RawQuery.html +7 -7
- package/docs/classes/Request.html +7 -5
- package/docs/classes/Response.html +2 -2
- package/docs/classes/ResponseData.html +3 -3
- package/docs/classes/ServiceProvider.html +2 -2
- package/docs/classes/ServiceResponse.html +2 -2
- package/docs/classes/SetSessionVariableQuery.html +7 -7
- package/docs/classes/StormError.html +5 -5
- package/docs/classes/TemporaryTableQuery.html +7 -7
- package/docs/classes/TimeoutError.html +5 -5
- package/docs/classes/Token.html +2 -2
- package/docs/classes/TokenManager.html +4 -4
- package/docs/classes/Transaction.html +2 -2
- package/docs/classes/UnauthorizedAccessError.html +5 -5
- package/docs/enums/ErrorCode.html +2 -2
- package/docs/enums/ExitCode.html +2 -2
- package/docs/enums/HTTPMethod.html +2 -2
- package/docs/enums/IsolationLevel.html +2 -2
- package/docs/enums/JWTError.html +2 -2
- package/docs/enums/StatusCode.html +2 -2
- package/docs/enums/TransactionAccessLevel.html +2 -2
- package/docs/functions/getInstance.html +1 -1
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +1 -1
- package/docs/interfaces/IAdditionalErrorDetails.html +1 -1
- package/docs/interfaces/ICloudwatchConfig.html +2 -2
- package/docs/interfaces/ICloudwatchCredentials.html +2 -2
- package/docs/interfaces/ICloudwatchStreamConfig.html +2 -2
- package/docs/interfaces/IConfig.html +4 -3
- package/docs/interfaces/IDatabaseConfig.html +2 -2
- package/docs/interfaces/IDatabaseConnection.html +5 -5
- package/docs/interfaces/IDatabasePosition.html +2 -2
- package/docs/interfaces/IErrorResponse.html +2 -2
- package/docs/interfaces/IFormData.html +2 -2
- package/docs/interfaces/IGetMySQLVersionResult.html +2 -2
- package/docs/interfaces/IGetMySQLVersionRow.html +2 -2
- package/docs/interfaces/IHistogramConfig.html +5 -0
- package/docs/interfaces/IInsertQueryResult.html +2 -2
- package/docs/interfaces/IJWTVerifyOptions.html +2 -2
- package/docs/interfaces/IMetricConfig.html +4 -0
- package/docs/interfaces/IMetricCounter.html +2 -0
- package/docs/interfaces/IMetricGauge.html +4 -0
- package/docs/interfaces/IMetricHistogram.html +3 -0
- package/docs/interfaces/IOKPacket.html +2 -2
- package/docs/interfaces/IParameterMap.html +1 -1
- package/docs/interfaces/IQueryable.html +2 -2
- package/docs/interfaces/IRequestResponse.html +2 -2
- package/docs/interfaces/ISetSessionVariableQueryInput.html +2 -2
- package/docs/interfaces/IStormCLIArgs.html +3 -2
- package/docs/interfaces/ITemporaryTableQueryInput.html +2 -2
- package/docs/interfaces/IUpdateQueryResult.html +2 -2
- package/docs/interfaces/formidable.FileJSON.html +1 -1
- package/docs/interfaces/formidable.Part.html +1 -1
- package/docs/types/IDeleteQueryResult.html +1 -1
- package/docs/types/IStoredProcedureResult.html +1 -1
- package/docs/types/TCoordinate.html +1 -1
- package/docs/types/TExpiresIn.html +1 -1
- package/docs/types/TSerializableResponse.html +1 -1
- package/docs/types/TSupportedResponsePrimitives.html +1 -1
- package/docs/types/TSupportedResponseTypes.html +1 -1
- package/lib/Application.d.ts +13 -0
- package/lib/Application.js +39 -5
- package/lib/Application.js.map +1 -1
- package/lib/ConfigLoader.js +18 -0
- package/lib/ConfigLoader.js.map +1 -1
- package/lib/Database.js +2 -2
- package/lib/Database.js.map +1 -1
- package/lib/Handler.d.ts +1 -0
- package/lib/Handler.js +14 -0
- package/lib/Handler.js.map +1 -1
- package/lib/IConfig.d.ts +5 -0
- package/lib/MetricStore.d.ts +34 -7
- package/lib/MetricStore.js +96 -31
- package/lib/MetricStore.js.map +1 -1
- package/lib/MySQLConnection.d.ts +3 -1
- package/lib/MySQLConnection.js +3 -3
- package/lib/MySQLConnection.js.map +1 -1
- package/lib/MySQLDatabase.d.ts +1 -0
- package/lib/MySQLDatabase.js +6 -2
- package/lib/MySQLDatabase.js.map +1 -1
- package/lib/PrometheusServer.d.ts +13 -0
- package/lib/PrometheusServer.js +89 -0
- package/lib/PrometheusServer.js.map +1 -0
- package/lib/Request.d.ts +4 -0
- package/lib/Request.js +6 -0
- package/lib/Request.js.map +1 -1
- package/lib/api.d.ts +1 -1
- package/lib/api.js.map +1 -1
- package/package.json +11 -11
- package/src/Application.ts +51 -6
- package/src/ConfigLoader.ts +18 -0
- package/src/Database.ts +2 -2
- package/src/Handler.ts +15 -0
- package/src/IConfig.ts +7 -1
- package/src/MetricStore.ts +136 -38
- package/src/MySQLConnection.ts +5 -3
- package/src/MySQLDatabase.ts +9 -3
- package/src/PrometheusServer.ts +109 -0
- package/src/Request.ts +7 -0
- package/src/api.ts +8 -1
- package/lib/handlers/HealthHandler.d.ts +0 -13
- package/lib/handlers/HealthHandler.js +0 -22
- package/lib/handlers/HealthHandler.js.map +0 -1
- package/src/handlers/HealthHandler.ts +0 -37
package/src/MetricStore.ts
CHANGED
|
@@ -1,61 +1,159 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
import * as prom from 'prom-client';
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
|
|
4
|
+
export interface IMetricConfig {
|
|
5
|
+
name: string;
|
|
6
|
+
help: string;
|
|
7
|
+
labelNames?: string[];
|
|
8
|
+
}
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
export interface IMetricData {
|
|
11
|
+
type: string;
|
|
12
|
+
content: string;
|
|
13
|
+
}
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
export interface IHistogramConfig extends IMetricConfig {
|
|
16
|
+
buckets?: number[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface IMetricCounter {
|
|
20
|
+
inc(value?: number): void;
|
|
21
|
+
inc(labels: Record<string, string | number>, value?: number): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface IMetricGauge {
|
|
25
|
+
set(value: number): void;
|
|
26
|
+
set(labels: Record<string, string | number>, value: number): void;
|
|
27
|
+
inc(value?: number): void;
|
|
28
|
+
inc(labels: Record<string, string | number>, value?: number): void;
|
|
29
|
+
dec(value?: number): void;
|
|
30
|
+
dec(labels: Record<string, string | number>, value?: number): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface IMetricHistogram {
|
|
34
|
+
observe(value: number): void;
|
|
35
|
+
observe(labels: Record<string, string | number>, value: number): void;
|
|
36
|
+
startTimer(labels?: Record<string, string | number>): (labels?: Record<string, string | number>) => number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class CounterWrapper implements IMetricCounter {
|
|
40
|
+
private $inner: prom.Counter;
|
|
41
|
+
public constructor(config: IMetricConfig) {
|
|
42
|
+
this.$inner = new prom.Counter({
|
|
43
|
+
name: config.name,
|
|
44
|
+
help: config.help,
|
|
45
|
+
labelNames: config.labelNames ?? []
|
|
46
|
+
});
|
|
11
47
|
}
|
|
48
|
+
public inc(labelsOrValue?: Record<string, string | number> | number, value?: number): void {
|
|
49
|
+
if (typeof labelsOrValue === 'number') {
|
|
50
|
+
this.$inner.inc(labelsOrValue);
|
|
51
|
+
}
|
|
52
|
+
else if (labelsOrValue !== undefined) {
|
|
53
|
+
this.$inner.inc(labelsOrValue, value);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.$inner.inc();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class GaugeWrapper implements IMetricGauge {
|
|
62
|
+
private $inner: prom.Gauge;
|
|
63
|
+
public constructor(config: IMetricConfig) {
|
|
64
|
+
this.$inner = new prom.Gauge({
|
|
65
|
+
name: config.name,
|
|
66
|
+
help: config.help,
|
|
67
|
+
labelNames: config.labelNames ?? []
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
public set(labelsOrValue: Record<string, string | number> | number, value?: number): void {
|
|
71
|
+
if (typeof labelsOrValue === 'number') {
|
|
72
|
+
this.$inner.set(labelsOrValue);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this.$inner.set(labelsOrValue, value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
public inc(labelsOrValue?: Record<string, string | number> | number, value?: number): void {
|
|
79
|
+
if (typeof labelsOrValue === 'number') {
|
|
80
|
+
this.$inner.inc(labelsOrValue);
|
|
81
|
+
}
|
|
82
|
+
else if (labelsOrValue !== undefined) {
|
|
83
|
+
this.$inner.inc(labelsOrValue, value);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
this.$inner.inc();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
public dec(labelsOrValue?: Record<string, string | number> | number, value?: number): void {
|
|
90
|
+
if (typeof labelsOrValue === 'number') {
|
|
91
|
+
this.$inner.dec(labelsOrValue);
|
|
92
|
+
}
|
|
93
|
+
else if (labelsOrValue !== undefined) {
|
|
94
|
+
this.$inner.dec(labelsOrValue, value);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.$inner.dec();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
class HistogramWrapper implements IMetricHistogram {
|
|
103
|
+
private $inner: prom.Histogram;
|
|
104
|
+
public constructor(config: IHistogramConfig) {
|
|
105
|
+
this.$inner = new prom.Histogram({
|
|
106
|
+
name: config.name,
|
|
107
|
+
help: config.help,
|
|
108
|
+
labelNames: config.labelNames ?? [],
|
|
109
|
+
...(config.buckets !== undefined ? { buckets: config.buckets } : {})
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
public observe(labelsOrValue: Record<string, string | number> | number, value?: number): void {
|
|
113
|
+
if (typeof labelsOrValue === 'number') {
|
|
114
|
+
this.$inner.observe(labelsOrValue);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.$inner.observe(labelsOrValue, value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
public startTimer(labels?: Record<string, string | number>): (labels?: Record<string, string | number>) => number {
|
|
121
|
+
return this.$inner.startTimer(labels);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class MetricStore {
|
|
126
|
+
private static $instance: MetricStore;
|
|
127
|
+
|
|
128
|
+
private constructor() {}
|
|
12
129
|
|
|
13
130
|
public static getInstance(): MetricStore {
|
|
14
131
|
if (!MetricStore.$instance) {
|
|
15
132
|
MetricStore.$instance = new MetricStore();
|
|
16
133
|
}
|
|
17
|
-
|
|
18
134
|
return MetricStore.$instance;
|
|
19
135
|
}
|
|
20
136
|
|
|
21
|
-
public
|
|
22
|
-
|
|
137
|
+
public setDefaultLabels(labels: Record<string, string>): void {
|
|
138
|
+
prom.register.setDefaultLabels(labels);
|
|
23
139
|
}
|
|
24
140
|
|
|
25
|
-
public
|
|
26
|
-
|
|
141
|
+
public createCounter(config: IMetricConfig): IMetricCounter {
|
|
142
|
+
return new CounterWrapper(config);
|
|
27
143
|
}
|
|
28
144
|
|
|
29
|
-
public
|
|
30
|
-
|
|
31
|
-
if (value === undefined) return null;
|
|
32
|
-
return value;
|
|
145
|
+
public createGauge(config: IMetricConfig): IMetricGauge {
|
|
146
|
+
return new GaugeWrapper(config);
|
|
33
147
|
}
|
|
34
148
|
|
|
35
|
-
public
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!value) {
|
|
39
|
-
value = 0;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (typeof value !== 'number') {
|
|
43
|
-
this.set(key, 0);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
value++;
|
|
48
|
-
this.set(key, value);
|
|
149
|
+
public createHistogram(config: IHistogramConfig): IMetricHistogram {
|
|
150
|
+
return new HistogramWrapper(config);
|
|
49
151
|
}
|
|
50
152
|
|
|
51
|
-
public
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
value--;
|
|
59
|
-
this.set(key, value);
|
|
153
|
+
public async getMetrics(): Promise<IMetricData> {
|
|
154
|
+
return {
|
|
155
|
+
type: prom.register.contentType,
|
|
156
|
+
content: await prom.register.metrics()
|
|
157
|
+
};
|
|
60
158
|
}
|
|
61
159
|
}
|
package/src/MySQLConnection.ts
CHANGED
|
@@ -40,7 +40,7 @@ import { GetProcessList, IGetProcessListOutput } from './private/GetProcessList'
|
|
|
40
40
|
import { GetMySQLVersion, IGetMySQLVersionResult } from './GetMySQLVersion';
|
|
41
41
|
import { GetPrimaryPositionQuery } from './private/GetPrimaryPositionQuery';
|
|
42
42
|
import { queryFormatter } from './mysql/queryFormatter';
|
|
43
|
-
import {
|
|
43
|
+
import { IMetricGauge } from './MetricStore';
|
|
44
44
|
|
|
45
45
|
const DEFAULT_HIGH_WATERMARK: number = 512; // in number of result objects
|
|
46
46
|
const TAG: string = 'MySQLConnection';
|
|
@@ -69,8 +69,9 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
|
|
|
69
69
|
private $hasReplicationEnabled: boolean;
|
|
70
70
|
private $isMasterConnection: boolean;
|
|
71
71
|
private $version: IGetMySQLVersionResult;
|
|
72
|
+
private $activeConnectionsGauge: IMetricGauge | null;
|
|
72
73
|
|
|
73
|
-
public constructor(connection: MySQL.PoolConnection, instantiationStack: string, isReadOnly: boolean = true) {
|
|
74
|
+
public constructor(connection: MySQL.PoolConnection, instantiationStack: string, isReadOnly: boolean = true, activeConnectionsGauge: IMetricGauge | null = null) {
|
|
74
75
|
connection.config.namedPlaceholders = true;
|
|
75
76
|
|
|
76
77
|
if (!getInstance().getConfig().enableMySQL2BreakingChanges) {
|
|
@@ -109,6 +110,7 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
|
|
|
109
110
|
this.$opened = true;
|
|
110
111
|
this.$transaction = false;
|
|
111
112
|
this.$isMasterConnection = null;
|
|
113
|
+
this.$activeConnectionsGauge = activeConnectionsGauge;
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
/**
|
|
@@ -349,6 +351,7 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
|
|
|
349
351
|
}
|
|
350
352
|
|
|
351
353
|
this.$opened = false;
|
|
354
|
+
this.$activeConnectionsGauge?.dec();
|
|
352
355
|
|
|
353
356
|
if (forceClose) {
|
|
354
357
|
if (this.isTransaction()) {
|
|
@@ -362,6 +365,5 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
|
|
|
362
365
|
}
|
|
363
366
|
|
|
364
367
|
this.getAPI().release();
|
|
365
|
-
MetricStore.getInstance().decrement('mysql.active_connections');
|
|
366
368
|
}
|
|
367
369
|
}
|
package/src/MySQLDatabase.ts
CHANGED
|
@@ -21,12 +21,13 @@ import {getInstance} from './instance';
|
|
|
21
21
|
import { IDatabasePosition } from './IDatabasePosition';
|
|
22
22
|
import { ConnectionReplicationWaiter } from './private/ConnectionReplicationWaiter';
|
|
23
23
|
import { ILogger } from '@arashi/interfaces';
|
|
24
|
-
import { MetricStore } from './MetricStore';
|
|
24
|
+
import { IMetricGauge, MetricStore } from './MetricStore';
|
|
25
25
|
|
|
26
26
|
const TAG: string = 'MySQLDatabase';
|
|
27
27
|
|
|
28
28
|
export class MySQLDatabase extends Database<MySQL.PoolOptions, MySQL.PoolConnection> {
|
|
29
29
|
private $cluster: MySQL.PoolCluster;
|
|
30
|
+
private $activeConnectionsGauge: IMetricGauge;
|
|
30
31
|
|
|
31
32
|
constructor() {
|
|
32
33
|
super();
|
|
@@ -38,6 +39,11 @@ export class MySQLDatabase extends Database<MySQL.PoolOptions, MySQL.PoolConnect
|
|
|
38
39
|
this.$cluster.on('enqueue', () => {
|
|
39
40
|
getInstance().getLogger().warn(TAG, 'Waiting for available connection...');
|
|
40
41
|
});
|
|
42
|
+
|
|
43
|
+
this.$activeConnectionsGauge = MetricStore.getInstance().createGauge({
|
|
44
|
+
name: 'storm_mysql_active_connections',
|
|
45
|
+
help: 'Number of MySQL connections currently claimed from the pool'
|
|
46
|
+
});
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
public escape(value: any): string {
|
|
@@ -70,8 +76,8 @@ export class MySQLDatabase extends Database<MySQL.PoolOptions, MySQL.PoolConnect
|
|
|
70
76
|
return;
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
resolve(new MySQLConnection(connection, instantationStack, !requireWriteAccess));
|
|
79
|
+
this.$activeConnectionsGauge.inc();
|
|
80
|
+
resolve(new MySQLConnection(connection, instantationStack, !requireWriteAccess, this.$activeConnectionsGauge));
|
|
75
81
|
});
|
|
76
82
|
});
|
|
77
83
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2017-2026 Norman Breau
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Application } from './Application';
|
|
18
|
+
import * as http from 'node:http';
|
|
19
|
+
import { IConfig } from './IConfig';
|
|
20
|
+
import { IMetricData, MetricStore } from './MetricStore';
|
|
21
|
+
|
|
22
|
+
const TAG: string = 'PrometheusServer';
|
|
23
|
+
const RETRY_DELAY: number = 5000;
|
|
24
|
+
|
|
25
|
+
export class PrometheusServer {
|
|
26
|
+
private $app: Application;
|
|
27
|
+
private $socket: http.Server;
|
|
28
|
+
private $bind: string;
|
|
29
|
+
private $port: number;
|
|
30
|
+
private $isClosing: boolean;
|
|
31
|
+
private $retryTimer: NodeJS.Timeout;
|
|
32
|
+
|
|
33
|
+
public constructor(app: Application) {
|
|
34
|
+
this.$app = app;
|
|
35
|
+
this.$socket = null;
|
|
36
|
+
this.$isClosing = false;
|
|
37
|
+
this.$retryTimer = null;
|
|
38
|
+
|
|
39
|
+
let config: IConfig = app.getConfig();
|
|
40
|
+
|
|
41
|
+
this.$bind = config.prometheus?.bind || '127.0.0.1';
|
|
42
|
+
this.$port = config.prometheus?.port;
|
|
43
|
+
|
|
44
|
+
if (!this.$port) {
|
|
45
|
+
app.getLogger().warn(TAG, 'Using default port algorithm for Prometheus. Better to explicitly set a port via --prometheus-port.');
|
|
46
|
+
this.$port = app.getDefaultPortForPrometheus();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public start(): void {
|
|
51
|
+
this.$app.getLogger().info(TAG, 'Initializing Prometheus');
|
|
52
|
+
void this.$createSocket();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private $createSocket(): Promise<void> {
|
|
56
|
+
if (this.$isClosing) {
|
|
57
|
+
return Promise.resolve();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return new Promise<void>((resolve, reject) => {
|
|
61
|
+
this.$socket = http.createServer(async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
|
62
|
+
let data: IMetricData = await MetricStore.getInstance().getMetrics();
|
|
63
|
+
res.setHeader('Content-Type', data.type);
|
|
64
|
+
res.end(data.content);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.$socket.once('error', (err: Error) => {
|
|
68
|
+
this.$socket = null;
|
|
69
|
+
resolve();
|
|
70
|
+
|
|
71
|
+
if (this.$isClosing) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.$app.getLogger().error(TAG, 'Prometheus Socket Error');
|
|
76
|
+
this.$app.getLogger().error(TAG, err);
|
|
77
|
+
|
|
78
|
+
this.$retryTimer = setTimeout(() => {
|
|
79
|
+
void this.$createSocket();
|
|
80
|
+
}, RETRY_DELAY);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
this.$socket.listen(this.$port, this.$bind, null, () => {
|
|
84
|
+
this.$app.getLogger().info(TAG, `Prometheus Server bounded`);
|
|
85
|
+
resolve();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public async close(): Promise<void> {
|
|
91
|
+
this.$isClosing = true;
|
|
92
|
+
clearTimeout(this.$retryTimer);
|
|
93
|
+
return new Promise<void>((resolve, reject) => {
|
|
94
|
+
if (!this.$socket) {
|
|
95
|
+
resolve();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.$socket.close((err?: Error) => {
|
|
100
|
+
if (err) {
|
|
101
|
+
reject(err);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
resolve();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
package/src/Request.ts
CHANGED
|
@@ -149,6 +149,13 @@ export class Request<TBody = any, TAuthToken extends IAuthTokenData = IAuthToken
|
|
|
149
149
|
return this.$request.params[name];
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Returns the matched route
|
|
154
|
+
*/
|
|
155
|
+
public getRoute(): string {
|
|
156
|
+
return this.$request.route.path;
|
|
157
|
+
}
|
|
158
|
+
|
|
152
159
|
/**
|
|
153
160
|
* Gets a URL parameter as string. If the value is multiple
|
|
154
161
|
* then only the first value is returned.
|
package/src/api.ts
CHANGED
|
@@ -105,7 +105,14 @@ export {TokenManager, TExpiresIn} from './TokenManager';
|
|
|
105
105
|
|
|
106
106
|
// Utils
|
|
107
107
|
export {ExitCode} from './ExitCode';
|
|
108
|
-
export {
|
|
108
|
+
export {
|
|
109
|
+
MetricStore,
|
|
110
|
+
IHistogramConfig,
|
|
111
|
+
IMetricConfig,
|
|
112
|
+
IMetricCounter,
|
|
113
|
+
IMetricGauge,
|
|
114
|
+
IMetricHistogram
|
|
115
|
+
} from './MetricStore';
|
|
109
116
|
|
|
110
117
|
// Database Objects
|
|
111
118
|
export {TCoordinate} from './TCoordinate';
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { IAuthTokenData } from '@arashi/token';
|
|
2
|
-
import { Application } from '../Application';
|
|
3
|
-
import { Handler } from '../Handler';
|
|
4
|
-
import { Request } from '../Request';
|
|
5
|
-
export interface IHealthHandlerMySQLStats {
|
|
6
|
-
activeConnections: number;
|
|
7
|
-
}
|
|
8
|
-
export interface IHealthHandlerOutput {
|
|
9
|
-
mysql: IHealthHandlerMySQLStats;
|
|
10
|
-
}
|
|
11
|
-
export declare class HealthHandler extends Handler<Application, void, IHealthHandlerOutput> {
|
|
12
|
-
protected _get(request: Request<void, IAuthTokenData>): Promise<IHealthHandlerOutput>;
|
|
13
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HealthHandler = void 0;
|
|
4
|
-
const Handler_1 = require("../Handler");
|
|
5
|
-
const MetricStore_1 = require("../MetricStore");
|
|
6
|
-
const ForbiddenError_1 = require("../ForbiddenError");
|
|
7
|
-
class HealthHandler extends Handler_1.Handler {
|
|
8
|
-
async _get(request) {
|
|
9
|
-
if (request.getIP() !== '127.0.0.1') {
|
|
10
|
-
throw new ForbiddenError_1.ForbiddenError();
|
|
11
|
-
}
|
|
12
|
-
let metrics = MetricStore_1.MetricStore.getInstance();
|
|
13
|
-
let out = {
|
|
14
|
-
mysql: {
|
|
15
|
-
activeConnections: metrics.get('mysql.active_connections')
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
return out;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
exports.HealthHandler = HealthHandler;
|
|
22
|
-
//# sourceMappingURL=HealthHandler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HealthHandler.js","sourceRoot":"","sources":["../../src/handlers/HealthHandler.ts"],"names":[],"mappings":";;;AAGA,wCAAmC;AAEnC,gDAA6C;AAC7C,sDAAmD;AAUnD,MAAa,aAAc,SAAQ,iBAIlC;IACsB,KAAK,CAAC,IAAI,CAAC,OAAsC;QAEhE,IAAI,OAAO,CAAC,KAAK,EAAE,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,IAAI,+BAAc,EAAE,CAAC;QAC/B,CAAC;QAED,IAAI,OAAO,GAAgB,yBAAW,CAAC,WAAW,EAAE,CAAC;QACrD,IAAI,GAAG,GAAyB;YAC5B,KAAK,EAAE;gBACH,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAW;aACvE;SACJ,CAAC;QAEF,OAAO,GAAG,CAAC;IACf,CAAC;CACJ;AApBD,sCAoBC"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { IAuthTokenData } from '@arashi/token';
|
|
3
|
-
import { Application } from '../Application';
|
|
4
|
-
import {Handler} from '../Handler';
|
|
5
|
-
import { Request } from '../Request';
|
|
6
|
-
import { MetricStore } from '../MetricStore';
|
|
7
|
-
import { ForbiddenError } from '../ForbiddenError';
|
|
8
|
-
|
|
9
|
-
export interface IHealthHandlerMySQLStats {
|
|
10
|
-
activeConnections: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface IHealthHandlerOutput {
|
|
14
|
-
mysql: IHealthHandlerMySQLStats;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class HealthHandler extends Handler<
|
|
18
|
-
Application,
|
|
19
|
-
void,
|
|
20
|
-
IHealthHandlerOutput
|
|
21
|
-
> {
|
|
22
|
-
protected override async _get(request: Request<void, IAuthTokenData>): Promise<IHealthHandlerOutput> {
|
|
23
|
-
|
|
24
|
-
if (request.getIP() !== '127.0.0.1') {
|
|
25
|
-
throw new ForbiddenError();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let metrics: MetricStore = MetricStore.getInstance();
|
|
29
|
-
let out: IHealthHandlerOutput = {
|
|
30
|
-
mysql: {
|
|
31
|
-
activeConnections: metrics.get('mysql.active_connections') as number
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
return out;
|
|
36
|
-
}
|
|
37
|
-
}
|