@viplance/nestjs-logger 0.4.7 → 0.4.8
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/dist/log.module.js +7 -2
- package/dist/log.module.js.map +1 -1
- package/dist/services/log.service.d.ts +1 -1
- package/dist/services/log.service.js +48 -6
- package/dist/services/log.service.js.map +1 -1
- package/dist/services/memory-db.service.d.ts +6 -0
- package/dist/services/memory-db.service.js +85 -1
- package/dist/services/memory-db.service.js.map +1 -1
- package/dist/services/ws.service.d.ts +2 -4
- package/dist/services/ws.service.js +61 -32
- package/dist/services/ws.service.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +3 -1
- package/public/scripts/common.js +139 -30
- package/public/scripts/details-popup.js +2 -2
- package/public/scripts/ws.js +31 -5
- package/public/styles/index.css +177 -2
- package/src/log.module.ts +8 -2
- package/src/services/log.service.ts +62 -5
- package/src/services/memory-db.service.ts +90 -3
- package/src/services/ws.service.ts +33 -36
|
@@ -63,10 +63,99 @@ export class MemoryDbService {
|
|
|
63
63
|
entity: EntitySchema,
|
|
64
64
|
options?: {
|
|
65
65
|
select?: string[];
|
|
66
|
+
where?: any;
|
|
67
|
+
order?: { [key: string]: 'ASC' | 'DESC' };
|
|
68
|
+
take?: number;
|
|
69
|
+
skip?: number;
|
|
66
70
|
}
|
|
67
71
|
): Promise<any[]> {
|
|
68
72
|
const table = this.getTableName(entity);
|
|
73
|
+
let data = [...this.db[table]];
|
|
74
|
+
|
|
75
|
+
// filter by search if where contains $or or Like (simplified for memory db)
|
|
76
|
+
// filter by search if where contains $or or Like (simplified for memory db)
|
|
77
|
+
if (options?.where) {
|
|
78
|
+
if (options.where.$or) {
|
|
79
|
+
const search = options.where.$or[0].message.$regex;
|
|
80
|
+
if (search) {
|
|
81
|
+
const regex = new RegExp(search, 'i');
|
|
82
|
+
data = data.filter(
|
|
83
|
+
(item) => regex.test(item.message) || regex.test(item.trace || '')
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
} else if (Array.isArray(options.where)) {
|
|
87
|
+
// handle Like constraints
|
|
88
|
+
const searchItem = options.where.find((w: any) => w.message);
|
|
89
|
+
if (searchItem && searchItem.message) {
|
|
90
|
+
let search = '';
|
|
91
|
+
if (typeof searchItem.message === 'string') {
|
|
92
|
+
search = searchItem.message.replace(/%/g, '');
|
|
93
|
+
} else if (searchItem.message.value) {
|
|
94
|
+
// FindOperator
|
|
95
|
+
search = searchItem.message.value.replace(/%/g, '');
|
|
96
|
+
} else if (searchItem.message._value) {
|
|
97
|
+
// FindOperator private
|
|
98
|
+
search = searchItem.message._value.replace(/%/g, '');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (search) {
|
|
102
|
+
const regex = new RegExp(search, 'i');
|
|
103
|
+
data = data.filter(
|
|
104
|
+
(item) => regex.test(item.message) || regex.test(item.trace || '')
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Handle type filtering
|
|
111
|
+
let types: string[] | null = null;
|
|
112
|
+
let typeVal: any;
|
|
113
|
+
|
|
114
|
+
if (Array.isArray(options.where)) {
|
|
115
|
+
typeVal = options.where[0]?.type;
|
|
116
|
+
} else {
|
|
117
|
+
typeVal = options.where.type;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (typeVal) {
|
|
121
|
+
if (Array.isArray(typeVal)) {
|
|
122
|
+
types = typeVal;
|
|
123
|
+
} else if (typeVal.value && Array.isArray(typeVal.value)) {
|
|
124
|
+
types = typeVal.value;
|
|
125
|
+
} else if (typeVal._value && Array.isArray(typeVal._value)) {
|
|
126
|
+
types = typeVal._value;
|
|
127
|
+
} else if (typeVal.$in && Array.isArray(typeVal.$in)) {
|
|
128
|
+
types = typeVal.$in;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (types) {
|
|
133
|
+
data = data.filter((item) => types!.includes(item.type));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// sort
|
|
138
|
+
if (options?.order) {
|
|
139
|
+
const field = Object.keys(options.order)[0];
|
|
140
|
+
const direction = options.order[field];
|
|
141
|
+
data.sort((a, b) => {
|
|
142
|
+
if (a[field] < b[field]) return direction === 'ASC' ? -1 : 1;
|
|
143
|
+
if (a[field] > b[field]) return direction === 'ASC' ? 1 : -1;
|
|
144
|
+
return 0;
|
|
145
|
+
});
|
|
146
|
+
} else {
|
|
147
|
+
data.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// pagination
|
|
151
|
+
if (options?.skip !== undefined) {
|
|
152
|
+
data = data.slice(options.skip);
|
|
153
|
+
}
|
|
154
|
+
if (options?.take !== undefined) {
|
|
155
|
+
data = data.slice(0, options.take);
|
|
156
|
+
}
|
|
69
157
|
|
|
158
|
+
// mapping (select)
|
|
70
159
|
let mapOptions = (obj: any) => obj; // return the object as is by default
|
|
71
160
|
|
|
72
161
|
if (options?.select) {
|
|
@@ -81,9 +170,7 @@ export class MemoryDbService {
|
|
|
81
170
|
};
|
|
82
171
|
}
|
|
83
172
|
|
|
84
|
-
return Promise.resolve(
|
|
85
|
-
this.db[table].map(mapOptions).sort((a, b) => b.updatedAt - a.updatedAt)
|
|
86
|
-
);
|
|
173
|
+
return Promise.resolve(data.map(mapOptions));
|
|
87
174
|
}
|
|
88
175
|
|
|
89
176
|
public async getOneById(entity: EntitySchema, _id: string): Promise<any> {
|
|
@@ -6,14 +6,14 @@ import { Subject } from 'rxjs';
|
|
|
6
6
|
@Injectable()
|
|
7
7
|
export class WsService {
|
|
8
8
|
public onMessage: Subject<any> = new Subject();
|
|
9
|
-
private
|
|
10
|
-
private connected: boolean = false;
|
|
9
|
+
private clients: Set<any> = new Set();
|
|
11
10
|
private connectionTimeout: number = 500;
|
|
12
11
|
private options: LogModuleOptions['websocket'] = {
|
|
13
12
|
port: 8080,
|
|
14
13
|
host: 'localhost',
|
|
15
14
|
};
|
|
16
15
|
private key: string = '';
|
|
16
|
+
private wsServer: any | null = null;
|
|
17
17
|
|
|
18
18
|
setupConnection(options: LogModuleOptions['websocket'], key = '') {
|
|
19
19
|
this.options = {
|
|
@@ -23,11 +23,11 @@ export class WsService {
|
|
|
23
23
|
this.key = key;
|
|
24
24
|
|
|
25
25
|
// Set up Web Socket server
|
|
26
|
-
if (this.
|
|
26
|
+
if (this.wsServer) {
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
this.wsServer = new WebSocketServer({
|
|
31
31
|
retryCount: 1,
|
|
32
32
|
reconnectInterval: 1,
|
|
33
33
|
handshakeTimeout: this.connectionTimeout,
|
|
@@ -38,45 +38,44 @@ export class WsService {
|
|
|
38
38
|
`Logs WebSocket server is listening on port ${this.options.port}`
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
-
wsServer.on('error', this.handleError);
|
|
42
|
-
wsServer.on('
|
|
43
|
-
wsServer.on('
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
this.wsServer.on('error', this.handleError);
|
|
42
|
+
this.wsServer.on('listening', () => this.handleOpenConnection());
|
|
43
|
+
this.wsServer.on('close', () => {
|
|
44
|
+
console.log('WebSocket server closed.');
|
|
45
|
+
this.wsServer = null;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
this.wsServer.on('connection', (connection: any) => {
|
|
49
|
+
this.clients.add(connection);
|
|
50
|
+
|
|
51
|
+
connection.on('message', (message: any) => this.handleMessage(message));
|
|
52
|
+
|
|
53
|
+
connection.on('close', () => {
|
|
54
|
+
this.clients.delete(connection);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
connection.on('error', () => {
|
|
58
|
+
this.clients.delete(connection);
|
|
59
|
+
});
|
|
49
60
|
});
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
sendMessage(message: any) {
|
|
53
|
-
this.
|
|
64
|
+
this.clients.forEach((client) => {
|
|
65
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
66
|
+
client.send(JSON.stringify(message));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
private handleError = () => {
|
|
57
72
|
const serverUrl = this.getServerUrl();
|
|
58
73
|
console.error(`Server ${serverUrl} is not available.`);
|
|
59
74
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
private closeConnection = (connection: any) => {
|
|
64
|
-
clearTimeout(connection.pingTimeout);
|
|
65
|
-
|
|
66
|
-
if (this.connected) {
|
|
67
|
-
console.log('Connection has been closed by server.');
|
|
68
|
-
this.connected = false;
|
|
69
|
-
this.handleError();
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
private ping = (connection: any) => {
|
|
74
|
-
console.log('Ping remote server.');
|
|
75
|
-
clearTimeout(connection.pingTimeout);
|
|
75
|
+
// If server failed, reset instance so retry can happen
|
|
76
|
+
this.wsServer = null;
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
connection.terminate();
|
|
79
|
-
}, 30000 + this.connectionTimeout);
|
|
78
|
+
setTimeout(() => this.setupConnection(this.options, this.key), this.connectionTimeout);
|
|
80
79
|
};
|
|
81
80
|
|
|
82
81
|
private handleMessage = (message: any) => {
|
|
@@ -97,13 +96,11 @@ export class WsService {
|
|
|
97
96
|
};
|
|
98
97
|
|
|
99
98
|
private getServerUrl = (): string => {
|
|
100
|
-
return `${this.options?.secure ? 'wss' : 'ws'}://${this.options?.host}:${
|
|
101
|
-
|
|
102
|
-
}`;
|
|
99
|
+
return `${this.options?.secure ? 'wss' : 'ws'}://${this.options?.host}:${this.options?.port
|
|
100
|
+
}`;
|
|
103
101
|
};
|
|
104
102
|
|
|
105
103
|
private handleOpenConnection = async () => {
|
|
106
|
-
this.connected = true;
|
|
107
104
|
const serverUrl = this.getServerUrl();
|
|
108
105
|
console.log(`${serverUrl} has been connected.`);
|
|
109
106
|
};
|