Refine log messages.
[e-mobility-charging-stations-simulator.git] / src / utils / Statistics.ts
... / ...
CommitLineData
1import CommandStatistics, { CommandStatisticsData, PerfEntry } from '../types/CommandStatistics';
2
3import CircularArray from './CircularArray';
4import Configuration from './Configuration';
5import Constants from './Constants';
6import { PerformanceEntry } from 'perf_hooks';
7import Utils from './Utils';
8import logger from './Logger';
9
10export default class Statistics {
11 private static instance: Statistics;
12 private _objName: string;
13 private _commandsStatistics: CommandStatistics;
14
15 private constructor() {
16 this._commandsStatistics = {} as CommandStatistics;
17 }
18
19 set objName(objName: string) {
20 this._objName = objName;
21 }
22
23 static getInstance(): Statistics {
24 if (!Statistics.instance) {
25 Statistics.instance = new Statistics();
26 }
27 return Statistics.instance;
28 }
29
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++;
35 } else {
36 this._commandsStatistics[command] = {} as CommandStatisticsData;
37 this._commandsStatistics[command].countRequest = 1;
38 }
39 break;
40 case Constants.OCPP_JSON_CALL_RESULT_MESSAGE:
41 if (this._commandsStatistics[command]) {
42 if (this._commandsStatistics[command].countResponse) {
43 this._commandsStatistics[command].countResponse++;
44 } else {
45 this._commandsStatistics[command].countResponse = 1;
46 }
47 } else {
48 this._commandsStatistics[command] = {} as CommandStatisticsData;
49 this._commandsStatistics[command].countResponse = 1;
50 }
51 break;
52 case Constants.OCPP_JSON_CALL_ERROR_MESSAGE:
53 if (this._commandsStatistics[command]) {
54 if (this._commandsStatistics[command].countError) {
55 this._commandsStatistics[command].countError++;
56 } else {
57 this._commandsStatistics[command].countError = 1;
58 }
59 } else {
60 this._commandsStatistics[command] = {} as CommandStatisticsData;
61 this._commandsStatistics[command].countError = 1;
62 }
63 break;
64 default:
65 logger.error(`${this._logPrefix()} Wrong message type ${messageType}`);
66 break;
67 }
68 }
69
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);
78 }
79
80 start(): void {
81 this._displayInterval();
82 }
83
84 private _display(): void {
85 logger.info(this._logPrefix() + ' %j', this._commandsStatistics);
86 }
87
88 private _displayInterval(): void {
89 if (Configuration.getStatisticsDisplayInterval() > 0) {
90 setInterval(() => {
91 this._display();
92 }, Configuration.getStatisticsDisplayInterval() * 1000);
93 logger.info(this._logPrefix() + ' displayed every ' + Utils.secondsToHHMMSS(Configuration.getStatisticsDisplayInterval()));
94 }
95 }
96
97 private median(dataSet: number[]): number {
98 if (Array.isArray(dataSet) && dataSet.length === 1) {
99 return dataSet[0];
100 }
101 const sortedDataSet = dataSet.slice().sort();
102 const middleIndex = Math.floor(sortedDataSet.length / 2);
103 if (sortedDataSet.length % 2) {
104 return sortedDataSet[middleIndex / 2];
105 }
106 return (sortedDataSet[(middleIndex - 1)] + sortedDataSet[middleIndex]) / 2;
107 }
108
109 private addPerformanceTimer(command: string, duration: number): void {
110 // Map to proper command name
111 const MAPCOMMAND = {
112 sendMeterValues: 'MeterValues',
113 startTransaction: 'StartTransaction',
114 stopTransaction: 'StopTransaction',
115 };
116 if (MAPCOMMAND[command]) {
117 command = MAPCOMMAND[command] as string;
118 }
119 // Initialize command statistics
120 if (!this._commandsStatistics[command]) {
121 this._commandsStatistics[command] = {} as CommandStatisticsData;
122 }
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);
132 }
133
134 private _logPrefix(): string {
135 return Utils.logPrefix(` ${this._objName} Statistics:`);
136 }
137}