@5minds/node-red-contrib-processcube-elasticsearch 0.4.0 → 1.0.0-develop-31b02f-m6dsjh20

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.
@@ -5,9 +5,11 @@
5
5
  "private": true,
6
6
  "dependencies": {
7
7
  "@flowfuse/node-red-dashboard": "1.22.0",
8
- "passport-oauth2": "*",
8
+ "do-red": "~1.0.7",
9
9
  "jsonwebtoken": "*",
10
10
  "jwks-rsa": "*",
11
- "node-red-contrib-oauth2": "*"
11
+ "node-red-contrib-oauth2": "*",
12
+ "node-red-contrib-opentelemetry": "~1.6.2",
13
+ "passport-oauth2": "*"
12
14
  }
13
- }
15
+ }
package/Dockerfile CHANGED
@@ -9,6 +9,9 @@ RUN cd /package_src/ && npm install
9
9
 
10
10
  RUN npm install /package_src/
11
11
 
12
+ # test pckages
13
+ RUN npm install do-red
14
+
12
15
  # defaults
13
16
  USER node-red
14
17
 
@@ -18,13 +18,12 @@ services:
18
18
  - ./.processcube/nodered:/data
19
19
 
20
20
  elasticsearch:
21
- image: docker.elastic.co/elasticsearch/elasticsearch:8.10.1
21
+ image: elasticsearch:8.16.3
22
22
  container_name: elasticsearch
23
23
  environment:
24
24
  - discovery.type=single-node
25
25
  - xpack.security.enabled=false
26
26
  - xpack.security.http.ssl.enabled=false
27
- # - ELASTIC_PASSWORD=myelasticpassword
28
27
  - ES_JAVA_OPTS=-Xms512m -Xmx512m
29
28
  ports:
30
29
  - "9200:9200"
@@ -33,6 +32,32 @@ services:
33
32
  - es_data:/usr/share/elasticsearch/data
34
33
  restart: always
35
34
 
35
+ apm-server:
36
+ image: elastic/apm-server:8.16.3
37
+ container_name: apm-server
38
+ environment:
39
+ - output.elasticsearch.hosts=["http://elasticsearch:9200"]
40
+ - apm-server.host=0.0.0.0:8200
41
+ - apm-server.enable=true
42
+ - apm-server.instrumentation.enabled=true
43
+ - apm-server.instrumentation.otlp.enabled=true # Aktiviert OpenTelemetry
44
+ - apm-server.instrumentation.otlp.http.endpoint=/v1/traces
45
+ ports:
46
+ - "8200:8200" # OpenTelemetry-Endpunkt
47
+ depends_on:
48
+ - elasticsearch
49
+
50
+ kibana:
51
+ image: kibana:8.16.3
52
+ container_name: kibana
53
+ environment:
54
+ - xpack.security.enabled=false
55
+ - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
56
+ ports:
57
+ - "5601:5601"
58
+ depends_on:
59
+ - elasticsearch
60
+
36
61
  volumes:
37
62
  es_data:
38
63
  driver: local
@@ -2,55 +2,6 @@
2
2
 
3
3
  const winston = require('winston');
4
4
  const winstonElasticSearch = require('winston-elasticsearch');
5
- const { ElasticsearchTransformer } = require('winston-elasticsearch');
6
-
7
- const logLevels = {
8
- levels: {
9
- Error: 0,
10
- Warning: 1,
11
- Information: 2,
12
- Debug: 3
13
- }
14
- };
15
-
16
- function transformElasticFields(logData) {
17
- const transformed = ElasticsearchTransformer(logData);
18
-
19
- transformed['@timestamp'] = logData.timestamp ? logData.timestamp : new Date().toISOString();
20
- transformed.message = logData.message;
21
- transformed.messageTemplate = logData.messageTemplate;
22
- transformed.severity = logData.level;
23
- transformed.level = logData.level;
24
- transformed.fields = logData.meta;
25
-
26
- if (logData.meta['transaction.id']) {
27
- transformed.transaction = { id: logData.meta['transaction.id'] };
28
- }
29
-
30
- if (logData.meta['trace.id']) {
31
- transformed.trace = {
32
- id: logData.meta['trace.id']
33
- };
34
- }
35
-
36
- if (logData.meta['span.id']) {
37
- transformed.span = {
38
- id: logData.meta['span.id']
39
- };
40
- }
41
-
42
- return transformed;
43
- }
44
-
45
- function raiseErrorAndSetNodeStatus(node, message) {
46
- node.error(message, {});
47
- node.status({
48
- fill: 'red',
49
- shape: 'ring',
50
- text: message,
51
- });
52
- }
53
-
54
5
 
55
6
  // TODO: MM winston-elasticsearch/index.js#112 wird die log als async function deklariert,
56
7
  // aber nicht als async aufgerufen
@@ -58,9 +9,26 @@ process.on('unhandledRejection', (reason, promise) => {
58
9
  console.error(`Unhandled Rejection at ${promise} reason: ${reason}`, {});
59
10
  });
60
11
 
61
-
62
12
  module.exports = function (RED) {
63
-
13
+
14
+ const logLevels = {
15
+ levels: {
16
+ Error: 0,
17
+ Warning: 1,
18
+ Information: 2,
19
+ Debug: 3
20
+ }
21
+ };
22
+
23
+ function raiseErrorAndSetNodeStatus(node, message) {
24
+ node.error(message, {});
25
+ node.status({
26
+ fill: 'red',
27
+ shape: 'ring',
28
+ text: message,
29
+ });
30
+ }
31
+
64
32
  function LogElasticLoggerNode(config) {
65
33
  RED.nodes.createNode(this, config);
66
34
  const node = this;
@@ -91,66 +59,39 @@ module.exports = function (RED) {
91
59
  }
92
60
 
93
61
  if (url) {
94
- const transports = [];
95
- const elasticSearchTransport = new winstonElasticSearch.ElasticsearchTransport({
96
- clientOpts: {
97
- node: url,
98
- auth: {
99
- username: user,
100
- password: password,
101
- },
102
- ssl: {
103
- // accept any
104
- rejectUnauthorized: false,
105
- },
106
- },
107
- transformer: (logData) => transformElasticFields(logData),
108
- index: index,
109
- });
62
+ node._url = `${url}/${index}/_doc`;
110
63
 
111
- transports.push(elasticSearchTransport);
64
+ if (user && password) {
65
+ node._credentials = Buffer.from(`${user}:${password}`).toString('base64');
66
+ }
112
67
 
113
- elasticSearchTransport.on('error', (error) => {
114
- raiseErrorAndSetNodeStatus(node, `Error in elasticSearchTransport caught: ${error.message}`);
115
- });
68
+ }
116
69
 
117
- node.logger = new winston.createLogger({
118
- exitOnError: false,
119
- level: 'Debug',
120
- levels: logLevels.levels,
121
- transports: transports,
122
- });
70
+ node.addToLog = async (record) => {
71
+ const headers = {
72
+ 'Content-Type': 'application/json',
73
+ };
74
+
75
+ if (node._credentials) {
76
+ headers.Authorization = `Basic ${node._credentials}`;
77
+ }
123
78
 
124
- node.logger.on('error', (error) => {
125
- raiseErrorAndSetNodeStatus(node, `Error in logger caught: ${error.message}`);
79
+ const response = await fetch(node._url, {
80
+ method: 'POST',
81
+ headers,
82
+ body: JSON.stringify(record),
126
83
  });
127
84
 
128
- this.debug('elastic-search logger created');
129
- }
130
-
85
+ const result = await response.json();
86
+
87
+ return result;
88
+ };
131
89
 
132
90
  this.on('close', function () {
133
- // close logger
134
- if (node.logger) {
135
- node.logger.close();
136
- }
137
-
138
91
  node.debug('elastic-search logger closed');
139
92
  });
140
93
  }
141
94
 
142
- LogElasticLoggerNode.prototype.addToLog = function addTolog(loglevel, msg) {
143
- try {
144
- if (this.logger == null) {
145
- raiseErrorAndSetNodeStatus(this, `Elastic search logger is not initialized: ${JSON.stringify(msg)}`);
146
- } else {
147
- this.logger.log(loglevel, msg.payload.message, msg.payload.meta);
148
- }
149
- } catch (error) {
150
- this.error(error, msg);
151
- }
152
- };
153
-
154
95
  RED.nodes.registerType('elastic-search-logger', LogElasticLoggerNode, {
155
96
  credentials: {
156
97
  username: { type: 'text' },
@@ -17,7 +17,7 @@
17
17
  }
18
18
  },
19
19
  inputs: 1,
20
- outputs: 0,
20
+ outputs: 1,
21
21
  icon: "file.svg",
22
22
  align: "right",
23
23
  label: function () {
@@ -100,15 +100,20 @@
100
100
  </div>
101
101
  </script>
102
102
 
103
- <script type="text/x-red" data-help-name="elastic-search">
104
- <p>A logging node for Elastic Search using the winston and winston-elastic logging libraries</p>
105
- <h3>Details</h3>
106
- <p>Output <code>msg.payload</code> (or <code>msg.&lt;custom path&gt;</code>) or complete <code>msg</code> is used as input of the logged message.</p>
107
- <p>The Log Level (Error, Warning, Information, Debug) used can be configured in the node or can be set
108
- by <code>msg.loglevel</code> (or <code>msg.&lt;custom path&gt;</code>).
109
- If the content is not one of ('Error', 'Warning', 'Information', 'Debug'), 'Debug' will be used as fallback</p>
110
- <p>If <code>msg.meta</code> is set, the meta info Object will be added to the file and ElasticSearch output as a JSON string.</p>
103
+ <script type="text/markdown" data-help-name="elastic-search">
104
+ Sending Data to the Elastic Search.
111
105
 
112
- <h3>References</h3>
113
- <p>This node is based on parts of node-red-contrib-advance-logger</p>
114
- </script>
106
+ ## Inputs
107
+
108
+ : payload (object) : Will mapped to the record for elastic and meta-data are mapped to the key `fields`
109
+
110
+ ## Outputs
111
+
112
+ : payload (string) : The result of the elastic call.
113
+
114
+
115
+ ### References
116
+
117
+ - [The ProcessCube&copy; Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; platform
118
+ - [ProcessCube&copy; LowCode Integration](https://processcube.io/docs/node-red) - LowCode integration in ProcessCube&copy;
119
+ </script>
package/elastic-search.js CHANGED
@@ -6,11 +6,45 @@ module.exports = function (RED) {
6
6
  const Information = 'Information';
7
7
  const Debug = 'Debug';
8
8
 
9
+ function mapMessage(msg) {
10
+ const transformed = {};
11
+
12
+ transformed['@timestamp'] = msg.payload.timestamp ? msg.timestamp : new Date().toISOString();
13
+ transformed.message = msg.payload.message;
14
+ transformed.messageTemplate = msg.payload.messageTemplate;
15
+ transformed.severity = msg.payload.level;
16
+ transformed.level = msg.payload.level;
17
+ let meta = msg.payload.meta;
18
+
19
+ if (meta['transaction.id']) {
20
+ transformed.transaction = { id: meta['transaction.id'] };
21
+
22
+ delete meta['transaction.id'];
23
+ }
24
+
25
+ if (msg.payload.meta['trace.id']) {
26
+ transformed.trace = { id: meta['trace.id'] };
27
+
28
+ delete meta['trace.id'];
29
+ }
30
+
31
+ if (msg.payload.meta['span.id']) {
32
+ transformed.span = { id: meta['span.id'] };
33
+
34
+ delete meta['span.id'];
35
+ }
36
+
37
+ transformed.fields = meta;
38
+
39
+ return transformed;
40
+ }
41
+
42
+
9
43
  function LogElasticNode(config) {
10
44
  RED.nodes.createNode(this, config);
11
45
  const node = this;
12
46
 
13
- this.on('input', function (msg) {
47
+ this.on('input', async function (msg) {
14
48
  node.logger = RED.nodes.getNode(config.logger);
15
49
 
16
50
  let loglevel = config.loglevel || '';
@@ -35,7 +69,14 @@ module.exports = function (RED) {
35
69
  }
36
70
 
37
71
  try {
38
- node.logger.addToLog(level, msg);
72
+
73
+ const mappedMessage = mapMessage(msg);
74
+
75
+ const result = await node.logger.addToLog(mappedMessage);
76
+
77
+ msg.payload = result;
78
+
79
+ node.send(msg);
39
80
  } catch (err) {
40
81
  node.error(err);
41
82
  }
@@ -0,0 +1,222 @@
1
+ [
2
+ {
3
+ "id": "53b75a173ac5abcc",
4
+ "type": "tab",
5
+ "label": "Elasticsearch loggen",
6
+ "disabled": false,
7
+ "info": "",
8
+ "env": []
9
+ },
10
+ {
11
+ "id": "38edcaecf5968ff5",
12
+ "type": "group",
13
+ "z": "53b75a173ac5abcc",
14
+ "style": {
15
+ "stroke": "#999999",
16
+ "stroke-opacity": "1",
17
+ "fill": "none",
18
+ "fill-opacity": "1",
19
+ "label": true,
20
+ "label-position": "nw",
21
+ "color": "#a4a4a4"
22
+ },
23
+ "nodes": [
24
+ "0b2f670fec931f5f",
25
+ "443b329ab591c4dd",
26
+ "f4a0d7de5d04c121",
27
+ "946add545fa1db9f",
28
+ "0c15060915aac994"
29
+ ],
30
+ "x": 34,
31
+ "y": 19,
32
+ "w": 372,
33
+ "h": 202
34
+ },
35
+ {
36
+ "id": "4aae454884faa826",
37
+ "type": "group",
38
+ "z": "53b75a173ac5abcc",
39
+ "style": {
40
+ "stroke": "#999999",
41
+ "stroke-opacity": "1",
42
+ "fill": "none",
43
+ "fill-opacity": "1",
44
+ "label": true,
45
+ "label-position": "nw",
46
+ "color": "#a4a4a4"
47
+ },
48
+ "nodes": [
49
+ "f90f2ba54f023834",
50
+ "31dcfc340dae3780",
51
+ "59df2485b6c11412"
52
+ ],
53
+ "x": 34,
54
+ "y": 259,
55
+ "w": 372,
56
+ "h": 142
57
+ },
58
+ {
59
+ "id": "0b2f670fec931f5f",
60
+ "type": "elastic-search",
61
+ "z": "53b75a173ac5abcc",
62
+ "g": "38edcaecf5968ff5",
63
+ "name": "",
64
+ "logger": "e8672d361683672d",
65
+ "complete": "payload",
66
+ "loglevel": "Debug",
67
+ "x": 300,
68
+ "y": 120,
69
+ "wires": [
70
+ []
71
+ ]
72
+ },
73
+ {
74
+ "id": "443b329ab591c4dd",
75
+ "type": "inject",
76
+ "z": "53b75a173ac5abcc",
77
+ "g": "38edcaecf5968ff5",
78
+ "name": "",
79
+ "props": [
80
+ {
81
+ "p": "payload"
82
+ }
83
+ ],
84
+ "repeat": "",
85
+ "crontab": "",
86
+ "once": false,
87
+ "onceDelay": 0.1,
88
+ "topic": "",
89
+ "payload": "{\"message\":\"hello world\",\"messageTemplate\":\"a messageTemplate\",\"severity\":\"a severity\",\"level\":\"a level\",\"meta\":{\"firstField\":\"a FirstField\",\"secondField\":\"a SecondField\",\"transaction.id\":\"a transaction.id\",\"trace.id\":\"a trace.id\",\"span.id\":\"a span.id\"}}",
90
+ "payloadType": "json",
91
+ "x": 130,
92
+ "y": 120,
93
+ "wires": [
94
+ [
95
+ "0b2f670fec931f5f"
96
+ ]
97
+ ]
98
+ },
99
+ {
100
+ "id": "f4a0d7de5d04c121",
101
+ "type": "comment",
102
+ "z": "53b75a173ac5abcc",
103
+ "g": "38edcaecf5968ff5",
104
+ "name": "Handle log",
105
+ "info": "",
106
+ "x": 120,
107
+ "y": 60,
108
+ "wires": []
109
+ },
110
+ {
111
+ "id": "946add545fa1db9f",
112
+ "type": "catch",
113
+ "z": "53b75a173ac5abcc",
114
+ "g": "38edcaecf5968ff5",
115
+ "name": "",
116
+ "scope": null,
117
+ "uncaught": false,
118
+ "x": 120,
119
+ "y": 180,
120
+ "wires": [
121
+ [
122
+ "0c15060915aac994"
123
+ ]
124
+ ]
125
+ },
126
+ {
127
+ "id": "0c15060915aac994",
128
+ "type": "debug",
129
+ "z": "53b75a173ac5abcc",
130
+ "g": "38edcaecf5968ff5",
131
+ "name": "error",
132
+ "active": true,
133
+ "tosidebar": true,
134
+ "console": false,
135
+ "tostatus": false,
136
+ "complete": "true",
137
+ "targetType": "full",
138
+ "statusVal": "",
139
+ "statusType": "auto",
140
+ "x": 270,
141
+ "y": 180,
142
+ "wires": []
143
+ },
144
+ {
145
+ "id": "f90f2ba54f023834",
146
+ "type": "elastic-search",
147
+ "z": "53b75a173ac5abcc",
148
+ "g": "4aae454884faa826",
149
+ "name": "",
150
+ "logger": "3667972f5cb77061",
151
+ "complete": "payload",
152
+ "loglevel": "Debug",
153
+ "x": 300,
154
+ "y": 360,
155
+ "wires": [
156
+ []
157
+ ]
158
+ },
159
+ {
160
+ "id": "31dcfc340dae3780",
161
+ "type": "inject",
162
+ "z": "53b75a173ac5abcc",
163
+ "g": "4aae454884faa826",
164
+ "name": "",
165
+ "props": [
166
+ {
167
+ "p": "payload"
168
+ }
169
+ ],
170
+ "repeat": "",
171
+ "crontab": "",
172
+ "once": false,
173
+ "onceDelay": 0.1,
174
+ "topic": "",
175
+ "payload": "{\"message\":\"hello world\"}",
176
+ "payloadType": "json",
177
+ "x": 130,
178
+ "y": 360,
179
+ "wires": [
180
+ [
181
+ "f90f2ba54f023834"
182
+ ]
183
+ ]
184
+ },
185
+ {
186
+ "id": "59df2485b6c11412",
187
+ "type": "comment",
188
+ "z": "53b75a173ac5abcc",
189
+ "g": "4aae454884faa826",
190
+ "name": "Handle failed log",
191
+ "info": "",
192
+ "x": 140,
193
+ "y": 300,
194
+ "wires": []
195
+ },
196
+ {
197
+ "id": "e8672d361683672d",
198
+ "type": "elastic-search-logger",
199
+ "name": "Docker compose",
200
+ "url": "http://elasticsearch:9200",
201
+ "urlType": "str",
202
+ "usernameType": "str",
203
+ "passwordType": "str",
204
+ "indexType": "str",
205
+ "filename": "log-elastic.log",
206
+ "maxsize": 1,
207
+ "maxfiles": 2
208
+ },
209
+ {
210
+ "id": "3667972f5cb77061",
211
+ "type": "elastic-search-logger",
212
+ "name": "Failed docker compose",
213
+ "url": "",
214
+ "urlType": "str",
215
+ "usernameType": "str",
216
+ "passwordType": "str",
217
+ "indexType": "str",
218
+ "filename": "log-elastic.log",
219
+ "maxsize": 1,
220
+ "maxfiles": 2
221
+ }
222
+ ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5minds/node-red-contrib-processcube-elasticsearch",
3
- "version": "0.4.0",
3
+ "version": "1.0.0-develop-31b02f-m6dsjh20",
4
4
  "license": "MIT",
5
5
  "description": "Node-RED nodes for Elasticsearch",
6
6
  "scripts": {
@@ -36,10 +36,6 @@
36
36
  },
37
37
  "examples": "examples"
38
38
  },
39
- "dependencies": {
40
- "winston": "^3.17.0",
41
- "winston-elasticsearch": "^0.19.0"
42
- },
43
39
  "keywords": [
44
40
  "node-red",
45
41
  "processcube",