1 import CommandStatistics
, { CommandStatisticsData
, PerfEntry
} from
'../types/CommandStatistics';
3 import CircularArray from
'./CircularArray';
4 import Configuration from
'./Configuration';
5 import Constants from
'./Constants';
6 import { PerformanceEntry
} from
'perf_hooks';
7 import Utils from
'./Utils';
8 import logger from
'./Logger';
10 export default class Statistics
{
11 private static instance
: Statistics
;
12 private _objName
: string;
13 private _commandsStatistics
: CommandStatistics
;
15 private constructor() {
16 this._commandsStatistics
= {} as CommandStatistics
;
19 set
objName(objName
: string) {
20 this._objName
= objName
;
23 static getInstance(): Statistics
{
24 if (!Statistics
.instance
) {
25 Statistics
.instance
= new Statistics();
27 return Statistics
.instance
;
30 addMessage(command
: string, messageType
: number): void {
31 switch (messageType
) {
32 case Constants
.OCPP_JSON_CALL_MESSAGE
:
33 if (this._commandsStatistics
[command
] && this._commandsStatistics
[command
].countRequest
) {
34 this._commandsStatistics
[command
].countRequest
++;
36 this._commandsStatistics
[command
] = {} as CommandStatisticsData
;
37 this._commandsStatistics
[command
].countRequest
= 1;
40 case Constants
.OCPP_JSON_CALL_RESULT_MESSAGE
:
41 if (this._commandsStatistics
[command
]) {
42 if (this._commandsStatistics
[command
].countResponse
) {
43 this._commandsStatistics
[command
].countResponse
++;
45 this._commandsStatistics
[command
].countResponse
= 1;
48 this._commandsStatistics
[command
] = {} as CommandStatisticsData
;
49 this._commandsStatistics
[command
].countResponse
= 1;
52 case Constants
.OCPP_JSON_CALL_ERROR_MESSAGE
:
53 if (this._commandsStatistics
[command
]) {
54 if (this._commandsStatistics
[command
].countError
) {
55 this._commandsStatistics
[command
].countError
++;
57 this._commandsStatistics
[command
].countError
= 1;
60 this._commandsStatistics
[command
] = {} as CommandStatisticsData
;
61 this._commandsStatistics
[command
].countError
= 1;
65 logger
.error(`${this._logPrefix()} Wrong message type ${messageType}`);
70 logPerformance(entry
: PerformanceEntry
, className
: string): void {
71 this.addPerformanceTimer(entry
.name
, entry
.duration
);
72 const perfEntry
: PerfEntry
= {} as PerfEntry
;
73 perfEntry
.name
= entry
.name
;
74 perfEntry
.entryType
= entry
.entryType
;
75 perfEntry
.startTime
= entry
.startTime
;
76 perfEntry
.duration
= entry
.duration
;
77 logger
.info(`${this._logPrefix()} object ${className} method(s) performance entry: %j`, perfEntry
);
81 this._displayInterval();
84 private _display(): void {
85 logger
.info(this._logPrefix() + ' %j', this._commandsStatistics
);
88 private _displayInterval(): void {
89 if (Configuration
.getStatisticsDisplayInterval() > 0) {
92 }, Configuration
.getStatisticsDisplayInterval() * 1000);
93 logger
.info(this._logPrefix() + ' displayed every ' + Utils
.secondsToHHMMSS(Configuration
.getStatisticsDisplayInterval()));
97 private median(dataSet
: number[]): number {
98 if (Array.isArray(dataSet
) && dataSet
.length
=== 1) {
101 const sortedDataSet
= dataSet
.slice().sort();
102 const middleIndex
= Math.floor(sortedDataSet
.length
/ 2);
103 if (sortedDataSet
.length
% 2) {
104 return sortedDataSet
[middleIndex
/ 2];
106 return (sortedDataSet
[(middleIndex
- 1)] + sortedDataSet
[middleIndex
]) / 2;
109 private addPerformanceTimer(command
: string, duration
: number): void {
110 // Map to proper command name
112 sendMeterValues
: 'MeterValues',
113 startTransaction
: 'StartTransaction',
114 stopTransaction
: 'StopTransaction',
116 if (MAPCOMMAND
[command
]) {
117 command
= MAPCOMMAND
[command
] as string;
119 // Initialize command statistics
120 if (!this._commandsStatistics
[command
]) {
121 this._commandsStatistics
[command
] = {} as CommandStatisticsData
;
123 // Update current statistics timers
124 this._commandsStatistics
[command
].countTimeMeasurement
= this._commandsStatistics
[command
].countTimeMeasurement
? this._commandsStatistics
[command
].countTimeMeasurement
+ 1 : 1;
125 this._commandsStatistics
[command
].currentTimeMeasurement
= duration
;
126 this._commandsStatistics
[command
].minTimeMeasurement
= this._commandsStatistics
[command
].minTimeMeasurement
? (this._commandsStatistics
[command
].minTimeMeasurement
> duration
? duration
: this._commandsStatistics
[command
].minTimeMeasurement
) : duration
;
127 this._commandsStatistics
[command
].maxTimeMeasurement
= this._commandsStatistics
[command
].maxTimeMeasurement
? (this._commandsStatistics
[command
].maxTimeMeasurement
< duration
? duration
: this._commandsStatistics
[command
].maxTimeMeasurement
) : duration
;
128 this._commandsStatistics
[command
].totalTimeMeasurement
= this._commandsStatistics
[command
].totalTimeMeasurement
? this._commandsStatistics
[command
].totalTimeMeasurement
+ duration
: duration
;
129 this._commandsStatistics
[command
].avgTimeMeasurement
= this._commandsStatistics
[command
].totalTimeMeasurement
/ this._commandsStatistics
[command
].countTimeMeasurement
;
130 Array.isArray(this._commandsStatistics
[command
].timeMeasurementSeries
) ? this._commandsStatistics
[command
].timeMeasurementSeries
.push(duration
) : this._commandsStatistics
[command
].timeMeasurementSeries
= [duration
] as CircularArray
<number>;
131 this._commandsStatistics
[command
].medTimeMeasurement
= this.median(this._commandsStatistics
[command
].timeMeasurementSeries
);
134 private _logPrefix(): string {
135 return Utils
.logPrefix(` ${this._objName} Statistics:`);