@theotherwillembotha/node-red-plugincore 0.0.50
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/LICENSE +15 -0
- package/README.md +190 -0
- package/build/GenerateNodes.d.ts +2 -0
- package/build/GenerateNodes.d.ts.map +1 -0
- package/build/GenerateNodes.js +36 -0
- package/build/Nodes.html +1729 -0
- package/build/Nodes.js +32 -0
- package/build/Plugins.js +74 -0
- package/build/core/NodeConstructor.d.ts +188 -0
- package/build/core/NodeConstructor.d.ts.map +1 -0
- package/build/core/NodeConstructor.js +679 -0
- package/build/core/NodeGenerator.d.ts +37 -0
- package/build/core/NodeGenerator.d.ts.map +1 -0
- package/build/core/NodeGenerator.js +300 -0
- package/build/core/Utils.d.ts +7 -0
- package/build/core/Utils.d.ts.map +1 -0
- package/build/core/Utils.js +19 -0
- package/build/core/logger/LoggerDecorator.d.ts +2 -0
- package/build/core/logger/LoggerDecorator.d.ts.map +1 -0
- package/build/core/logger/LoggerDecorator.js +93 -0
- package/build/core/logger/node/ConsoleLoggerConfigNode.d.ts +16 -0
- package/build/core/logger/node/ConsoleLoggerConfigNode.d.ts.map +1 -0
- package/build/core/logger/node/ConsoleLoggerConfigNode.html +131 -0
- package/build/core/logger/node/ConsoleLoggerConfigNode.js +47 -0
- package/build/core/logger/node/LoggerConfigNode.d.ts +30 -0
- package/build/core/logger/node/LoggerConfigNode.d.ts.map +1 -0
- package/build/core/logger/node/LoggerConfigNode.html +307 -0
- package/build/core/logger/node/LoggerConfigNode.js +60 -0
- package/build/core/logger/node/LokiLoggerConfigNode.d.ts +20 -0
- package/build/core/logger/node/LokiLoggerConfigNode.d.ts.map +1 -0
- package/build/core/logger/node/LokiLoggerConfigNode.html +153 -0
- package/build/core/logger/node/LokiLoggerConfigNode.js +52 -0
- package/build/core/logger/node/RestLoggerConfigNode.d.ts +24 -0
- package/build/core/logger/node/RestLoggerConfigNode.d.ts.map +1 -0
- package/build/core/logger/node/RestLoggerConfigNode.html +209 -0
- package/build/core/logger/node/RestLoggerConfigNode.js +57 -0
- package/build/core/logger/service/LoggerService.d.ts +88 -0
- package/build/core/logger/service/LoggerService.d.ts.map +1 -0
- package/build/core/logger/service/LoggerService.js +204 -0
- package/build/core/logger/service/LoggerServiceTypes.d.ts +24 -0
- package/build/core/logger/service/LoggerServiceTypes.d.ts.map +1 -0
- package/build/core/logger/service/LoggerServiceTypes.js +30 -0
- package/build/core/logger/template/LoggerTemplate.d.ts +11 -0
- package/build/core/logger/template/LoggerTemplate.d.ts.map +1 -0
- package/build/core/logger/template/LoggerTemplate.html +328 -0
- package/build/core/logger/template/LoggerTemplate.js +12 -0
- package/build/core/metrics/MetricsDecorator.d.ts +40 -0
- package/build/core/metrics/MetricsDecorator.d.ts.map +1 -0
- package/build/core/metrics/MetricsDecorator.js +166 -0
- package/build/core/metrics/node/CounterMetricConfigNode.d.ts +16 -0
- package/build/core/metrics/node/CounterMetricConfigNode.d.ts.map +1 -0
- package/build/core/metrics/node/CounterMetricConfigNode.html +48 -0
- package/build/core/metrics/node/CounterMetricConfigNode.js +61 -0
- package/build/core/metrics/node/GaugeMetricConfigNode.d.ts +17 -0
- package/build/core/metrics/node/GaugeMetricConfigNode.d.ts.map +1 -0
- package/build/core/metrics/node/GaugeMetricConfigNode.html +48 -0
- package/build/core/metrics/node/GaugeMetricConfigNode.js +61 -0
- package/build/core/metrics/node/MetricsConfigNode.d.ts +14 -0
- package/build/core/metrics/node/MetricsConfigNode.d.ts.map +1 -0
- package/build/core/metrics/node/MetricsConfigNode.html +21 -0
- package/build/core/metrics/node/MetricsConfigNode.js +56 -0
- package/build/core/metrics/node/TimerMetricConfigNode.d.ts +28 -0
- package/build/core/metrics/node/TimerMetricConfigNode.d.ts.map +1 -0
- package/build/core/metrics/node/TimerMetricConfigNode.html +190 -0
- package/build/core/metrics/node/TimerMetricConfigNode.js +101 -0
- package/build/core/metrics/service/MetricsService.d.ts +187 -0
- package/build/core/metrics/service/MetricsService.d.ts.map +1 -0
- package/build/core/metrics/service/MetricsService.js +385 -0
- package/build/core/metrics/template/CounterMetricTemplate.d.ts +5 -0
- package/build/core/metrics/template/CounterMetricTemplate.d.ts.map +1 -0
- package/build/core/metrics/template/CounterMetricTemplate.html +40 -0
- package/build/core/metrics/template/CounterMetricTemplate.js +12 -0
- package/build/core/metrics/template/GaugeMetricTemplate.d.ts +5 -0
- package/build/core/metrics/template/GaugeMetricTemplate.d.ts.map +1 -0
- package/build/core/metrics/template/GaugeMetricTemplate.html +39 -0
- package/build/core/metrics/template/GaugeMetricTemplate.js +12 -0
- package/build/core/metrics/template/MetricsTemplate.d.ts +8 -0
- package/build/core/metrics/template/MetricsTemplate.d.ts.map +1 -0
- package/build/core/metrics/template/MetricsTemplate.html +54 -0
- package/build/core/metrics/template/MetricsTemplate.js +12 -0
- package/build/core/metrics/template/TimerMetricTemplate.d.ts +5 -0
- package/build/core/metrics/template/TimerMetricTemplate.d.ts.map +1 -0
- package/build/core/metrics/template/TimerMetricTemplate.html +39 -0
- package/build/core/metrics/template/TimerMetricTemplate.js +12 -0
- package/build/core/other/InputDecorator.d.ts +3 -0
- package/build/core/other/InputDecorator.d.ts.map +1 -0
- package/build/core/other/InputDecorator.js +43 -0
- package/build/core/other/service/InputService.d.ts +16 -0
- package/build/core/other/service/InputService.d.ts.map +1 -0
- package/build/core/other/service/InputService.js +31 -0
- package/build/core/other/service/SettingsService.d.ts +25 -0
- package/build/core/other/service/SettingsService.d.ts.map +1 -0
- package/build/core/other/service/SettingsService.js +74 -0
- package/build/core/other/template/BasicTemplate.d.ts +5 -0
- package/build/core/other/template/BasicTemplate.d.ts.map +1 -0
- package/build/core/other/template/BasicTemplate.html +76 -0
- package/build/core/other/template/BasicTemplate.js +11 -0
- package/build/core/other/template/SettingsTemplate.d.ts +5 -0
- package/build/core/other/template/SettingsTemplate.d.ts.map +1 -0
- package/build/core/other/template/SettingsTemplate.html +128 -0
- package/build/core/other/template/SettingsTemplate.js +11 -0
- package/build/core/tagging/NodeDescriptionDecorator.d.ts +17 -0
- package/build/core/tagging/NodeDescriptionDecorator.d.ts.map +1 -0
- package/build/core/tagging/NodeDescriptionDecorator.js +25 -0
- package/build/core/tagging/service/NodeTypeService.d.ts +15 -0
- package/build/core/tagging/service/NodeTypeService.d.ts.map +1 -0
- package/build/core/tagging/service/NodeTypeService.js +47 -0
- package/build/core/webhook/WebhookDecorator.d.ts +3 -0
- package/build/core/webhook/WebhookDecorator.d.ts.map +1 -0
- package/build/core/webhook/WebhookDecorator.js +45 -0
- package/build/core/webhook/node/WebhookServerConfigNode.d.ts +16 -0
- package/build/core/webhook/node/WebhookServerConfigNode.d.ts.map +1 -0
- package/build/core/webhook/node/WebhookServerConfigNode.html +61 -0
- package/build/core/webhook/node/WebhookServerConfigNode.js +40 -0
- package/build/core/webhook/service/ReverseProxyTypeService.d.ts +29 -0
- package/build/core/webhook/service/ReverseProxyTypeService.d.ts.map +1 -0
- package/build/core/webhook/service/ReverseProxyTypeService.js +24 -0
- package/build/core/webhook/service/WebhookServerService.d.ts +52 -0
- package/build/core/webhook/service/WebhookServerService.d.ts.map +1 -0
- package/build/core/webhook/service/WebhookServerService.js +146 -0
- package/build/core/webhook/template/WebhookTemplate.d.ts +22 -0
- package/build/core/webhook/template/WebhookTemplate.d.ts.map +1 -0
- package/build/core/webhook/template/WebhookTemplate.html +434 -0
- package/build/core/webhook/template/WebhookTemplate.js +12 -0
- package/build/index.d.ts +33 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +55 -0
- package/package.json +67 -0
- package/src/GenerateNodes.ts +42 -0
- package/src/core/NodeConstructor.ts +889 -0
- package/src/core/NodeGenerator.ts +331 -0
- package/src/core/Utils.ts +19 -0
- package/src/core/logger/LoggerDecorator.ts +105 -0
- package/src/core/logger/node/ConsoleLoggerConfigNode.html +131 -0
- package/src/core/logger/node/ConsoleLoggerConfigNode.ts +46 -0
- package/src/core/logger/node/LoggerConfigNode.html +307 -0
- package/src/core/logger/node/LoggerConfigNode.ts +95 -0
- package/src/core/logger/node/LokiLoggerConfigNode.html +153 -0
- package/src/core/logger/node/LokiLoggerConfigNode.ts +58 -0
- package/src/core/logger/node/RestLoggerConfigNode.html +209 -0
- package/src/core/logger/node/RestLoggerConfigNode.ts +67 -0
- package/src/core/logger/service/LoggerService.ts +317 -0
- package/src/core/logger/service/LoggerServiceTypes.ts +26 -0
- package/src/core/logger/template/LoggerTemplate.html +328 -0
- package/src/core/logger/template/LoggerTemplate.ts +23 -0
- package/src/core/metrics/MetricsDecorator.ts +227 -0
- package/src/core/metrics/node/CounterMetricConfigNode.html +48 -0
- package/src/core/metrics/node/CounterMetricConfigNode.ts +62 -0
- package/src/core/metrics/node/GaugeMetricConfigNode.html +48 -0
- package/src/core/metrics/node/GaugeMetricConfigNode.ts +62 -0
- package/src/core/metrics/node/MetricsConfigNode.html +21 -0
- package/src/core/metrics/node/MetricsConfigNode.ts +55 -0
- package/src/core/metrics/node/TimerMetricConfigNode.html +190 -0
- package/src/core/metrics/node/TimerMetricConfigNode.ts +118 -0
- package/src/core/metrics/service/MetricsService.ts +560 -0
- package/src/core/metrics/template/CounterMetricTemplate.html +40 -0
- package/src/core/metrics/template/CounterMetricTemplate.ts +15 -0
- package/src/core/metrics/template/GaugeMetricTemplate.html +39 -0
- package/src/core/metrics/template/GaugeMetricTemplate.ts +15 -0
- package/src/core/metrics/template/MetricsTemplate.html +54 -0
- package/src/core/metrics/template/MetricsTemplate.ts +18 -0
- package/src/core/metrics/template/TimerMetricTemplate.html +39 -0
- package/src/core/metrics/template/TimerMetricTemplate.ts +14 -0
- package/src/core/other/InputDecorator.ts +57 -0
- package/src/core/other/service/InputService.ts +36 -0
- package/src/core/other/service/SettingsService.ts +103 -0
- package/src/core/other/template/BasicTemplate.html +76 -0
- package/src/core/other/template/BasicTemplate.ts +15 -0
- package/src/core/other/template/SettingsTemplate.html +128 -0
- package/src/core/other/template/SettingsTemplate.ts +17 -0
- package/src/core/tagging/NodeDescriptionDecorator.ts +39 -0
- package/src/core/tagging/service/NodeTypeService.ts +67 -0
- package/src/core/webhook/WebhookDecorator.ts +70 -0
- package/src/core/webhook/node/WebhookServerConfigNode.html +61 -0
- package/src/core/webhook/node/WebhookServerConfigNode.ts +38 -0
- package/src/core/webhook/service/ReverseProxyTypeService.ts +46 -0
- package/src/core/webhook/service/WebhookServerService.ts +211 -0
- package/src/core/webhook/template/WebhookTemplate.html +434 -0
- package/src/core/webhook/template/WebhookTemplate.ts +36 -0
- package/src/index.ts +47 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
import {BaseNode, BaseNodeConfig, BaseService, FlowDeployment, ServiceDescriptor} from "../../NodeConstructor"
|
|
2
|
+
import client, {Counter, Gauge, Histogram, HistogramConfiguration, MetricObjectWithValues, MetricValueWithName, register as PrometheusRegistry, Registry, Summary, SummaryConfiguration } from "prom-client";
|
|
3
|
+
import { NodeAPI, NodeAPISettingsWithData } from "node-red";
|
|
4
|
+
import deepEqual from "deep-equal";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export abstract class Metric<ConfigType extends MetricConfig> {
|
|
8
|
+
private _config: ConfigType;
|
|
9
|
+
private _labels: Labels;
|
|
10
|
+
|
|
11
|
+
protected constructor(config:ConfigType){
|
|
12
|
+
this._config = config;
|
|
13
|
+
this._labels = {flow:config.node.flow, type:config.node.type, name:config.node.name, id:config.node.id, metric:config.metricname};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public labels():Labels {
|
|
17
|
+
return this._labels;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public config():ConfigType{
|
|
21
|
+
return this._config;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type MetricsReference = {
|
|
26
|
+
metricsEnabled:boolean,
|
|
27
|
+
metricsReference:string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// **************************************************** //
|
|
31
|
+
// Counter //
|
|
32
|
+
// **************************************************** //
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
type CounterCallback = {
|
|
36
|
+
(state:CounterState):void;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type CounterState = {
|
|
40
|
+
value:number,
|
|
41
|
+
labels:{}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface CounterMetricConfig extends MetricConfig {
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class CounterMetric extends Metric<CounterMetricConfig>{
|
|
49
|
+
private counter: Counter;
|
|
50
|
+
private internalCounter: Counter.Internal;
|
|
51
|
+
private subscribers:{[key:string]:CounterCallback} = {};
|
|
52
|
+
constructor(id:string, config:CounterMetricConfig, registry:client.Registry){
|
|
53
|
+
super(config);
|
|
54
|
+
|
|
55
|
+
this.counter = new Counter({
|
|
56
|
+
name: id,
|
|
57
|
+
help: (config.metricdescription) ? config.metricdescription: config.metricname,
|
|
58
|
+
labelNames: Object.keys(this.labels()),
|
|
59
|
+
registers: [registry]
|
|
60
|
+
});
|
|
61
|
+
this.counter.reset();
|
|
62
|
+
this.internalCounter = this.counter.labels(this.labels() as any);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public inc():CounterMetric{
|
|
66
|
+
this.internalCounter.inc();
|
|
67
|
+
this.get().then(state => Object.values(this.subscribers).forEach(callback => callback(state)));
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public async get():Promise<CounterState> {
|
|
72
|
+
return this.counter.get().then(t => t.values[0]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public reset():void{
|
|
76
|
+
this.counter.reset();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public subscribe(node:BaseNode<BaseNodeConfig>, callback:CounterCallback){
|
|
80
|
+
this.subscribers[node.id()] = callback;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public unsubscribe(node:BaseNode<BaseNodeConfig>){
|
|
84
|
+
delete this.subscribers[node.id()];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// **************************************************** //
|
|
89
|
+
// Gauge //
|
|
90
|
+
// **************************************************** //
|
|
91
|
+
type GaugeCallback = {
|
|
92
|
+
(state:GaugeState):void;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export interface GaugeState {
|
|
96
|
+
value: number
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface GaugeMetricConfig extends MetricConfig {
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export class GaugeMetric extends Metric<GaugeMetricConfig>{
|
|
104
|
+
private collector: number = 0;
|
|
105
|
+
private gauge:Gauge.Internal<string>;
|
|
106
|
+
private subscribers:{[key:string]:GaugeCallback} = {};
|
|
107
|
+
|
|
108
|
+
constructor(id:string, config:GaugeMetricConfig, registry:client.Registry){
|
|
109
|
+
super(config);
|
|
110
|
+
let _this = this;
|
|
111
|
+
|
|
112
|
+
this.gauge = new client.Gauge({
|
|
113
|
+
name: id,
|
|
114
|
+
help: (config.metricdescription) ? config.metricdescription: config.metricname,
|
|
115
|
+
registers: [registry],
|
|
116
|
+
labelNames: Object.keys(this.labels()),
|
|
117
|
+
// this function is called every time the stats are collected.
|
|
118
|
+
// the response value needs to be set.
|
|
119
|
+
collect() { this.labels(_this.labels() as {}).set(_this.collector); }
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public inc():GaugeMetric{
|
|
124
|
+
this.collector+=1;
|
|
125
|
+
let state:GaugeState = this.get();
|
|
126
|
+
Object.values(this.subscribers).forEach(sub => sub(state));
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public dec():GaugeMetric{
|
|
131
|
+
this.collector-=1;
|
|
132
|
+
let state:GaugeState = this.get();
|
|
133
|
+
Object.values(this.subscribers).forEach(sub => sub(state));
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public get():GaugeState {
|
|
138
|
+
return {
|
|
139
|
+
value:this.collector,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public reset():void {
|
|
144
|
+
this.collector = 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public subscribe(node:BaseNode<BaseNodeConfig>, callback:GaugeCallback){
|
|
148
|
+
this.subscribers[node.id()] = callback;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public unsubscribe(node:BaseNode<BaseNodeConfig>){
|
|
152
|
+
delete this.subscribers[node.id()];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// **************************************************** //
|
|
157
|
+
// Histogram //
|
|
158
|
+
// **************************************************** //
|
|
159
|
+
|
|
160
|
+
type HistogramCallback = {
|
|
161
|
+
(state:HistogramState):void;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export interface DefaultBucketConfig{
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface ManualBucketConfig{
|
|
169
|
+
intervals:number[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface LinearBucketConfig{
|
|
173
|
+
start:number;
|
|
174
|
+
interval:number;
|
|
175
|
+
count:number;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface ExponentialBucketConfig{
|
|
179
|
+
start:number;
|
|
180
|
+
factor:number;
|
|
181
|
+
count:number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface HistogramMetricConfig extends MetricConfig {
|
|
185
|
+
buckettype:BucketType,
|
|
186
|
+
bucketconfig:DefaultBucketConfig|ManualBucketConfig|LinearBucketConfig|ExponentialBucketConfig
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export enum BucketType{
|
|
190
|
+
default = "default",
|
|
191
|
+
manual = "manual",
|
|
192
|
+
linear = "linear",
|
|
193
|
+
exponential = "exponential"
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export class HistogramMetric extends Metric<HistogramMetricConfig> {
|
|
197
|
+
|
|
198
|
+
private histogram: client.Histogram<string>;
|
|
199
|
+
private subscribers:{[key:string]:HistogramCallback} = {};
|
|
200
|
+
|
|
201
|
+
constructor(id:string, config:HistogramMetricConfig, registry:Registry){
|
|
202
|
+
super(config);
|
|
203
|
+
|
|
204
|
+
// Build the Histogram Config.
|
|
205
|
+
let histogramConfig:HistogramConfiguration<string> = {
|
|
206
|
+
name: id,
|
|
207
|
+
help: (config.metricdescription) ? config.metricdescription: config.metricname,
|
|
208
|
+
labelNames: Object.keys(this.labels()),
|
|
209
|
+
registers:[registry]
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if(config.buckettype === BucketType.default){
|
|
213
|
+
let bucketConfig = (config.bucketconfig as DefaultBucketConfig);
|
|
214
|
+
// do nothing
|
|
215
|
+
}
|
|
216
|
+
if(config.buckettype === BucketType.manual){
|
|
217
|
+
let bucketConfig = (config.bucketconfig as ManualBucketConfig);
|
|
218
|
+
histogramConfig.buckets = bucketConfig.intervals;
|
|
219
|
+
}
|
|
220
|
+
if(config.buckettype === BucketType.linear){
|
|
221
|
+
let bucketConfig = (config.bucketconfig as LinearBucketConfig);
|
|
222
|
+
histogramConfig.buckets = client.linearBuckets(bucketConfig.start, bucketConfig.interval, bucketConfig.count);
|
|
223
|
+
}
|
|
224
|
+
if(config.buckettype === BucketType.exponential){
|
|
225
|
+
let bucketConfig = (config.bucketconfig as ExponentialBucketConfig);
|
|
226
|
+
histogramConfig.buckets = client.exponentialBuckets(bucketConfig.start, bucketConfig.factor, bucketConfig.count);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.histogram = new Histogram(histogramConfig);
|
|
230
|
+
this.histogram.zero(this.labels() as any);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public observe(value:number){
|
|
234
|
+
this.histogram.labels(this.labels() as any).observe(value);
|
|
235
|
+
this.get().then(status => Object.values(this.subscribers).forEach(subscriber => subscriber(status)));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public async get():Promise<HistogramState>{
|
|
239
|
+
return this.histogram.get().then(t => new HistogramState(t.values));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public subscribe(node:BaseNode<BaseNodeConfig>, callback:HistogramCallback){
|
|
243
|
+
this.subscribers[node.id()] = callback;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public unsubscribe(node:BaseNode<BaseNodeConfig>){
|
|
247
|
+
delete this.subscribers[node.id()];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
class HistogramState {
|
|
252
|
+
private _values: { labels: any; value: number; metricName?:string }[];
|
|
253
|
+
private _average: number | undefined;
|
|
254
|
+
|
|
255
|
+
constructor(values:{labels:any, value:number, metricName?:string}[]){
|
|
256
|
+
this._values = values;
|
|
257
|
+
|
|
258
|
+
let sum = this._values.find(value => value.metricName?.endsWith("_sum"))?.value;
|
|
259
|
+
let count = this._values.find(value => value.metricName?.endsWith("_count"))?.value;
|
|
260
|
+
this._average = (sum && count) ? sum/count : undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public average():number|undefined{
|
|
264
|
+
return this._average;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// **************************************************** //
|
|
269
|
+
// Summary //
|
|
270
|
+
// **************************************************** //
|
|
271
|
+
|
|
272
|
+
interface PercentileConfig{}
|
|
273
|
+
|
|
274
|
+
class SummaryState {
|
|
275
|
+
private _values: { labels: any; value: number; metricName?:string }[];
|
|
276
|
+
private _average: number | undefined;
|
|
277
|
+
|
|
278
|
+
constructor(values:{labels:any, value:number, metricName?:string}[]){
|
|
279
|
+
this._values = values;
|
|
280
|
+
|
|
281
|
+
let sum = this._values.find(value => value.metricName?.endsWith("_sum"))?.value;
|
|
282
|
+
let count = this._values.find(value => value.metricName?.endsWith("_count"))?.value;
|
|
283
|
+
this._average = (sum && count) ? sum/count : undefined;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
public average():number|undefined{
|
|
287
|
+
return this._average;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
type SummaryCallback = (state:SummaryState) => void
|
|
292
|
+
|
|
293
|
+
export interface DefaultPercentileConfig extends PercentileConfig {
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export interface ManualPercentileConfig extends PercentileConfig {
|
|
297
|
+
percentiles:number[]
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export interface SummaryMetricConfig extends MetricConfig {
|
|
301
|
+
percentileType:PercentileType,
|
|
302
|
+
percentileConfig:PercentileConfig
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export enum PercentileType {
|
|
306
|
+
default = "default",
|
|
307
|
+
manual = "manual"
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export class SummaryMetric extends Metric<SummaryMetricConfig> {
|
|
311
|
+
private summary: client.Summary;
|
|
312
|
+
private subscribers:{[key:string]:SummaryCallback} = {};
|
|
313
|
+
|
|
314
|
+
constructor(id:string, config:SummaryMetricConfig, registry:Registry){
|
|
315
|
+
super(config);
|
|
316
|
+
|
|
317
|
+
let summaryConfig:SummaryConfiguration<string> = {
|
|
318
|
+
name: id,
|
|
319
|
+
help: (config.metricdescription) ? config.metricdescription: config.metricname,
|
|
320
|
+
labelNames: Object.keys(this.labels()),
|
|
321
|
+
registers:[registry],
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
if(config.percentileType === PercentileType.default){
|
|
325
|
+
// do nothing.
|
|
326
|
+
let perceintileConfig:DefaultPercentileConfig = config.percentileConfig as DefaultPercentileConfig;
|
|
327
|
+
summaryConfig.percentiles = [0.01, 0.1, 0.9, 0.99];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if(config.percentileType === PercentileType.manual){
|
|
331
|
+
let percentilesConfig:ManualPercentileConfig = config.percentileConfig as ManualPercentileConfig;
|
|
332
|
+
summaryConfig.percentiles = percentilesConfig.percentiles;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
this.summary = new Summary(summaryConfig);
|
|
336
|
+
//this.summary.zero(this._labels as any);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
public observe(value:number){
|
|
340
|
+
this.summary.labels(this.labels() as any).observe(value);
|
|
341
|
+
this.get().then(status => Object.values(this.subscribers).forEach(subscriber => subscriber(status)));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
public async get():Promise<SummaryState>{
|
|
345
|
+
return this.summary.get().then(s => new SummaryState(s.values));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
public subscribe(node:BaseNode<BaseNodeConfig>, callback:SummaryCallback){
|
|
349
|
+
this.subscribers[node.id()] = callback;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public unsubscribe(node:BaseNode<BaseNodeConfig>){
|
|
353
|
+
delete this.subscribers[node.id()];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// **************************************************** //
|
|
358
|
+
// COMMONS //
|
|
359
|
+
// **************************************************** //
|
|
360
|
+
interface Labels {
|
|
361
|
+
flow:string;
|
|
362
|
+
type:string;
|
|
363
|
+
name:string;
|
|
364
|
+
id:string;
|
|
365
|
+
metric:string;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export class MetricsContainer {
|
|
369
|
+
private _config: MetricsConfig;
|
|
370
|
+
private _registry: client.Registry;
|
|
371
|
+
|
|
372
|
+
private counters:{[key:string]:CounterMetric} = {};
|
|
373
|
+
private histograms:{[key:string]:HistogramMetric} = {};
|
|
374
|
+
private gauges:{[key:string]:GaugeMetric} = {};
|
|
375
|
+
private summaries:{[key:string]:SummaryMetric} = {};
|
|
376
|
+
|
|
377
|
+
constructor(config:MetricsConfig){
|
|
378
|
+
this._config = config;
|
|
379
|
+
|
|
380
|
+
// create a registry with the config.
|
|
381
|
+
this._registry = new client.Registry();
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
close() {
|
|
386
|
+
this._registry.clear();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
public registry():client.Registry{
|
|
390
|
+
return this._registry;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// return true if the two configurations are not the same.
|
|
394
|
+
hasChanged(config: MetricsConfig): boolean {
|
|
395
|
+
return !(
|
|
396
|
+
this._config.metricsPath === config.metricsPath &&
|
|
397
|
+
this._config.metricsPort === config.metricsPort
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
public counter(config: CounterMetricConfig): CounterMetric{
|
|
402
|
+
const counterId = `counter_${config.node.id}`;
|
|
403
|
+
let counter:CounterMetric = this.counters[counterId];
|
|
404
|
+
if(counter){
|
|
405
|
+
// check if the config has changed much.
|
|
406
|
+
if(!deepEqual(counter.config(), config)){
|
|
407
|
+
this._registry.removeSingleMetric(counterId);
|
|
408
|
+
this.counters[counterId] = (counter = new CounterMetric(counterId, config, this._registry));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else{
|
|
412
|
+
this.counters[counterId] = (counter = new CounterMetric(counterId, config, this._registry));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return counter;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
public guage(config: GaugeMetricConfig): GaugeMetric {
|
|
419
|
+
var guageId = `gauge_${config.node.id}`;
|
|
420
|
+
var gauge:GaugeMetric = this.gauges[guageId];
|
|
421
|
+
if(gauge){
|
|
422
|
+
// check if the config has changed much.
|
|
423
|
+
if(!deepEqual(gauge.config(), config)){
|
|
424
|
+
this._registry.removeSingleMetric(guageId);
|
|
425
|
+
this.gauges[guageId] = (gauge = new GaugeMetric(guageId, config, this._registry));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else{
|
|
429
|
+
this.gauges[guageId] = (gauge = new GaugeMetric(guageId, config, this._registry));
|
|
430
|
+
}
|
|
431
|
+
return gauge;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public histogram(config: HistogramMetricConfig): HistogramMetric {
|
|
435
|
+
const histogramId = `histogram_${config.node.id}`;
|
|
436
|
+
let histogram:HistogramMetric = this.histograms[histogramId];
|
|
437
|
+
if(histogram){
|
|
438
|
+
// check if the config has changed much.
|
|
439
|
+
if(!deepEqual(histogram.config(), config)){
|
|
440
|
+
this._registry.removeSingleMetric(histogramId);
|
|
441
|
+
this.histograms[histogramId] = (histogram = new HistogramMetric(histogramId, config, this._registry));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else{
|
|
445
|
+
this.histograms[histogramId] = (histogram = new HistogramMetric(histogramId, config, this._registry));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return histogram;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
public summary(config: SummaryMetricConfig): SummaryMetric {
|
|
452
|
+
const summaryId = `summary_${config.node.id}`;
|
|
453
|
+
let summary:SummaryMetric = this.summaries[summaryId];
|
|
454
|
+
if(summary){
|
|
455
|
+
if(!deepEqual(summary.config(), config)){
|
|
456
|
+
this._registry.removeSingleMetric(summaryId);
|
|
457
|
+
this.summaries[summaryId] = (summary = new SummaryMetric(summaryId, config, this._registry));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
else{
|
|
461
|
+
this.summaries[summaryId] = (summary = new SummaryMetric(summaryId, config, this._registry));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return summary;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
export class MetricsService extends BaseService {
|
|
470
|
+
|
|
471
|
+
private static metrics:{[key:string]:MetricsContainer} = {};
|
|
472
|
+
private red!: NodeAPI<NodeAPISettingsWithData>;
|
|
473
|
+
|
|
474
|
+
public constructor(){
|
|
475
|
+
super("MetricsService");
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
public init(red: NodeAPI<NodeAPISettingsWithData>): void {
|
|
479
|
+
this.red = red;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
public deinit(red: NodeAPI<NodeAPISettingsWithData>): void {
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
public async onDeploy(deployment: FlowDeployment): Promise<void> {
|
|
486
|
+
// get the FlowElements.
|
|
487
|
+
let configNodes:{[key:string]:MetricsConfig} = {};
|
|
488
|
+
deployment.flows
|
|
489
|
+
.filter(element => element.type === "MetricsConfigNode")
|
|
490
|
+
.forEach(element => configNodes[element.id] = element as any as MetricsConfig);
|
|
491
|
+
|
|
492
|
+
// retire metrics that have been removed or that have changed.
|
|
493
|
+
Object.entries(MetricsService.metrics)
|
|
494
|
+
.filter(([id, metric]) => !configNodes[id] || metric.hasChanged(configNodes[id]))
|
|
495
|
+
.forEach(([id, metric]) => {
|
|
496
|
+
delete MetricsService.metrics[id];
|
|
497
|
+
metric.close();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// create the new metrics.
|
|
501
|
+
Object.entries(configNodes)
|
|
502
|
+
.filter(([id, metricConfig]) => !MetricsService.metrics[id])
|
|
503
|
+
.forEach(([id, metricConfig]) => {
|
|
504
|
+
MetricsService.metrics[id] = new MetricsContainer(metricConfig);
|
|
505
|
+
})
|
|
506
|
+
|
|
507
|
+
return Promise.resolve();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public static get(reference:MetricsReference):MetricsContainer{
|
|
511
|
+
return MetricsService.metrics[reference.metricsReference];
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
static override getServiceDescriptor():ServiceDescriptor {
|
|
515
|
+
return new ServiceDescriptor(
|
|
516
|
+
"@theotherwillembotha/metricsservice",
|
|
517
|
+
"MetricsService",
|
|
518
|
+
"services-plugin",
|
|
519
|
+
"@theotherwillembotha/node-red-plugincore",
|
|
520
|
+
MetricsService
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export interface MetricsConfig {
|
|
526
|
+
id:string,
|
|
527
|
+
metricsPath:string,
|
|
528
|
+
metricsPort:number,
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
export interface NodeReference {
|
|
532
|
+
name: string;
|
|
533
|
+
type: string;
|
|
534
|
+
flow: string;
|
|
535
|
+
id: string;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export interface MetricConfig{
|
|
539
|
+
node:NodeReference;
|
|
540
|
+
metricname: string;
|
|
541
|
+
metricdescription?: string;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/*
|
|
545
|
+
Quick explanation of how this is supposed to work:
|
|
546
|
+
|
|
547
|
+
when you deploy a new metricConfig, it should create an instance of "Metric" in the backend.
|
|
548
|
+
this instance should survive flow redeployments, but should be removed if the flow that
|
|
549
|
+
gets deployed no longer contains the metric. The idea is to not have the metrics reset between
|
|
550
|
+
flow deployments or to have the Metric / Repository become unavialable between deployments.
|
|
551
|
+
|
|
552
|
+
users should be able to access it in this way:
|
|
553
|
+
|
|
554
|
+
MetricsService.get(<MetricReference>).createCounter(<counterConfig>), though this is mostly just intended for use in the MetricConfigClass.
|
|
555
|
+
|
|
556
|
+
Normally, a handle on the MetricsService should be gained by pulling a reference to the MetricsConfigNode, eg
|
|
557
|
+
this._metrics = (NodeManager.RED.nodes.getNode(config.metricsReference) as any).node().metrics();
|
|
558
|
+
this._counter = this._metrics.counter(this, "messages", "Number of messages that have passed through this node");
|
|
559
|
+
|
|
560
|
+
*/
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script type="text/javascript" template-section="onCompose">
|
|
2
|
+
node
|
|
3
|
+
.addDefault("counterConfig", { type:"CounterMetricConfigNode", required: true })
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script type="text/javascript" template-section="onIncludeEditPrepare">
|
|
7
|
+
|
|
8
|
+
let metricsEnabled = $("#node-{{#if config.isConfigNode}}config-{{/if}}input-metricsEnabled");
|
|
9
|
+
let metricsEnabledSection = $("#section_metricsEnabled");
|
|
10
|
+
|
|
11
|
+
metricsEnabled.on('change', function() {
|
|
12
|
+
if(metricsEnabled.prop("checked")){
|
|
13
|
+
metricsEnabledSection.show();
|
|
14
|
+
node._def.defaults.metricsReference.required = true;
|
|
15
|
+
}
|
|
16
|
+
else{
|
|
17
|
+
metricsEnabledSection.hide()
|
|
18
|
+
node._def.defaults.metricsReference.required = false;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script type="text/javascript" template-section="onIncludeEditSave">
|
|
24
|
+
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<script type="text/html" template-section="onIncludeEditForm">
|
|
28
|
+
<!-- CounterMetric -->
|
|
29
|
+
<div id="section_countermetricconfig">
|
|
30
|
+
<div class="form-row">
|
|
31
|
+
<label for="node-input-counterConfig"><i class="fa fa-tag"></i> Counter</label>
|
|
32
|
+
<input type="text" id="node-input-counterConfig" />
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<script type="text/markdown" template-section="onIncludeDocumentation">
|
|
38
|
+
### Counter
|
|
39
|
+
: *counter* (counterconfig) : the counter that would be incremented whenever a message is received.
|
|
40
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SourceUtility } from "../../NodeGenerator";
|
|
2
|
+
import { Template, TemplateDescriptor } from "../../NodeConstructor"
|
|
3
|
+
import { CounterMetricConfigNode } from "../node/CounterMetricConfigNode";
|
|
4
|
+
|
|
5
|
+
export class CounterMetricTemplate extends Template {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
public static getTemplateDescriptor(): TemplateDescriptor {
|
|
9
|
+
return new TemplateDescriptor(
|
|
10
|
+
"countermetric",
|
|
11
|
+
CounterMetricTemplate,
|
|
12
|
+
SourceUtility.getSourcePath("/build/", "/src/") + "CounterMetricTemplate.html",
|
|
13
|
+
[CounterMetricConfigNode]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script type="text/javascript" template-section="onCompose">
|
|
2
|
+
node
|
|
3
|
+
.addDefault("gaugeConfig", { type:"GaugeMetricConfigNode", required: true })
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script type="text/javascript" template-section="onIncludeEditPrepare">
|
|
7
|
+
let metricsEnabled = $("#node-{{#if config.isConfigNode}}config-{{/if}}input-metricsEnabled");
|
|
8
|
+
let metricsEnabledSection = $("#section_metricsEnabled");
|
|
9
|
+
|
|
10
|
+
metricsEnabled.on('change', function() {
|
|
11
|
+
if(metricsEnabled.prop("checked")){
|
|
12
|
+
metricsEnabledSection.show();
|
|
13
|
+
node._def.defaults.metricsReference.required = true;
|
|
14
|
+
}
|
|
15
|
+
else{
|
|
16
|
+
metricsEnabledSection.hide()
|
|
17
|
+
node._def.defaults.metricsReference.required = false;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script type="text/javascript" template-section="onIncludeEditSave">
|
|
23
|
+
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<script type="text/html" template-section="onIncludeEditForm">
|
|
27
|
+
<!-- GaugeMetric -->
|
|
28
|
+
<div id="section_gaugemetricconfig">
|
|
29
|
+
<div class="form-row">
|
|
30
|
+
<label for="node-input-gaugeConfig"><i class="fa fa-tag"></i> Gauge</label>
|
|
31
|
+
<input type="text" id="node-input-gaugeConfig" />
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<script type="text/markdown" template-section="onIncludeDocumentation">
|
|
37
|
+
### Gauge
|
|
38
|
+
: *gauge* (gaugeconfig) : the gauge that would be incremented / decremented whenever a message is received.
|
|
39
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SourceUtility } from "../../NodeGenerator";
|
|
2
|
+
import { Template, TemplateDescriptor } from "../../NodeConstructor"
|
|
3
|
+
import { GaugeMetricConfigNode } from "../node/GaugeMetricConfigNode";
|
|
4
|
+
|
|
5
|
+
export class GaugeMetricTemplate extends Template {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
public static getTemplateDescriptor(): TemplateDescriptor {
|
|
9
|
+
return new TemplateDescriptor(
|
|
10
|
+
"gaugemetric",
|
|
11
|
+
GaugeMetricTemplate,
|
|
12
|
+
SourceUtility.getSourcePath("/build/", "/src/") + "GaugeMetricTemplate.html",
|
|
13
|
+
[GaugeMetricConfigNode]);
|
|
14
|
+
}
|
|
15
|
+
}
|