1 import CommandStatistics
, { CommandStatisticsData
, PerfEntry
} from
'../types/CommandStatistics';
2 import { IncomingRequestCommand
, RequestCommand
} from
'../types/ocpp/1.6/Requests';
4 import CircularArray from
'./CircularArray';
5 import Configuration from
'./Configuration';
6 import { MessageType
} from
'../types/ocpp/MessageType';
7 import { PerformanceEntry
} from
'perf_hooks';
8 import Utils from
'./Utils';
9 import logger from
'./Logger';
11 export default class Statistics
{
12 private static instance
: Statistics
;
13 public objName
: string;
14 private commandsStatistics
: CommandStatistics
;
16 private constructor() {
17 this.commandsStatistics
= {} as CommandStatistics
;
20 static getInstance(): Statistics
{
21 if (!Statistics
.instance
) {
22 Statistics
.instance
= new Statistics();
24 return Statistics
.instance
;
27 addMessage(command
: RequestCommand
| IncomingRequestCommand
, messageType
: MessageType
): void {
28 switch (messageType
) {
29 case MessageType
.CALL_MESSAGE
:
30 if (this.commandsStatistics
[command
] && this.commandsStatistics
[command
].countRequest
) {
31 this.commandsStatistics
[command
].countRequest
++;
33 this.commandsStatistics
[command
] = {} as CommandStatisticsData
;
34 this.commandsStatistics
[command
].countRequest
= 1;
37 case MessageType
.CALL_RESULT_MESSAGE
:
38 if (this.commandsStatistics
[command
]) {
39 if (this.commandsStatistics
[command
].countResponse
) {
40 this.commandsStatistics
[command
].countResponse
++;
42 this.commandsStatistics
[command
].countResponse
= 1;
45 this.commandsStatistics
[command
] = {} as CommandStatisticsData
;
46 this.commandsStatistics
[command
].countResponse
= 1;
49 case MessageType
.CALL_ERROR_MESSAGE
:
50 if (this.commandsStatistics
[command
]) {
51 if (this.commandsStatistics
[command
].countError
) {
52 this.commandsStatistics
[command
].countError
++;
54 this.commandsStatistics
[command
].countError
= 1;
57 this.commandsStatistics
[command
] = {} as CommandStatisticsData
;
58 this.commandsStatistics
[command
].countError
= 1;
62 logger
.error(`${this._logPrefix()} Wrong message type ${messageType}`);
67 logPerformance(entry
: PerformanceEntry
, className
: string): void {
68 this.addPerformanceTimer(entry
.name
as RequestCommand
| IncomingRequestCommand
, entry
.duration
);
69 const perfEntry
: PerfEntry
= {} as PerfEntry
;
70 perfEntry
.name
= entry
.name
;
71 perfEntry
.entryType
= entry
.entryType
;
72 perfEntry
.startTime
= entry
.startTime
;
73 perfEntry
.duration
= entry
.duration
;
74 logger
.info(`${this._logPrefix()} object ${className} method(s) performance entry: %j`, perfEntry
);
78 this._displayInterval();
81 private _display(): void {
82 logger
.info(this._logPrefix() + ' %j', this.commandsStatistics
);
85 private _displayInterval(): void {
86 if (Configuration
.getStatisticsDisplayInterval() > 0) {
89 }, Configuration
.getStatisticsDisplayInterval() * 1000);
90 logger
.info(this._logPrefix() + ' displayed every ' + Utils
.secondsToHHMMSS(Configuration
.getStatisticsDisplayInterval()));
94 private median(dataSet
: number[]): number {
95 if (Array.isArray(dataSet
) && dataSet
.length
=== 1) {
98 const sortedDataSet
= dataSet
.slice().sort();
99 const middleIndex
= Math.floor(sortedDataSet
.length
/ 2);
100 if (sortedDataSet
.length
% 2) {
101 return sortedDataSet
[middleIndex
/ 2];
103 return (sortedDataSet
[(middleIndex
- 1)] + sortedDataSet
[middleIndex
]) / 2;
106 private addPerformanceTimer(command
: RequestCommand
| IncomingRequestCommand
, duration
: number): void {
107 // Map to proper command name
109 sendMeterValues
: 'MeterValues',
110 startTransaction
: 'StartTransaction',
111 stopTransaction
: 'StopTransaction',
113 if (MAPCOMMAND
[command
]) {
114 command
= MAPCOMMAND
[command
] as RequestCommand
| IncomingRequestCommand
;
116 // Initialize command statistics
117 if (!this.commandsStatistics
[command
]) {
118 this.commandsStatistics
[command
] = {} as CommandStatisticsData
;
120 // Update current statistics timers
121 this.commandsStatistics
[command
].countTimeMeasurement
= this.commandsStatistics
[command
].countTimeMeasurement
? this.commandsStatistics
[command
].countTimeMeasurement
+ 1 : 1;
122 this.commandsStatistics
[command
].currentTimeMeasurement
= duration
;
123 this.commandsStatistics
[command
].minTimeMeasurement
= this.commandsStatistics
[command
].minTimeMeasurement
? (this.commandsStatistics
[command
].minTimeMeasurement
> duration
? duration
: this.commandsStatistics
[command
].minTimeMeasurement
) : duration
;
124 this.commandsStatistics
[command
].maxTimeMeasurement
= this.commandsStatistics
[command
].maxTimeMeasurement
? (this.commandsStatistics
[command
].maxTimeMeasurement
< duration
? duration
: this.commandsStatistics
[command
].maxTimeMeasurement
) : duration
;
125 this.commandsStatistics
[command
].totalTimeMeasurement
= this.commandsStatistics
[command
].totalTimeMeasurement
? this.commandsStatistics
[command
].totalTimeMeasurement
+ duration
: duration
;
126 this.commandsStatistics
[command
].avgTimeMeasurement
= this.commandsStatistics
[command
].totalTimeMeasurement
/ this.commandsStatistics
[command
].countTimeMeasurement
;
127 Array.isArray(this.commandsStatistics
[command
].timeMeasurementSeries
) ? this.commandsStatistics
[command
].timeMeasurementSeries
.push(duration
) : this.commandsStatistics
[command
].timeMeasurementSeries
= [duration
] as CircularArray
<number>;
128 this.commandsStatistics
[command
].medTimeMeasurement
= this.median(this.commandsStatistics
[command
].timeMeasurementSeries
);
131 private _logPrefix(): string {
132 return Utils
.logPrefix(` ${this.objName} Statistics:`);