@oas-tools/oas-telemetry 0.1.5 → 0.1.6

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/index.cjs CHANGED
@@ -7,36 +7,58 @@ exports.default = oasTelemetry;
7
7
  var _telemetry = require("./telemetry.cjs");
8
8
  var _express = require("express");
9
9
  var _v = _interopRequireDefault(require("v8"));
10
+ var _fs = require("fs");
11
+ var _path = _interopRequireDefault(require("path"));
12
+ var _jsYaml = _interopRequireDefault(require("js-yaml"));
13
+ var _url = require("url");
10
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
15
  // telemetryMiddleware.js
12
16
 
17
+ const _filename = (0, _url.fileURLToPath)(import.meta.url);
18
+ const _dirname = _path.default.dirname(_filename);
19
+ let telemetryStatus = {
20
+ active: true
21
+ };
22
+ let baseURL = '/telemetry';
13
23
  let telemetryConfig = {
14
24
  exporter: _telemetry.inMemoryExporter,
15
- baseURL: '/telemetry'
25
+ specFileName: ""
16
26
  };
17
27
  function oasTelemetry(tlConfig) {
18
28
  if (tlConfig) {
19
29
  console.log('Telemetry config provided');
20
30
  telemetryConfig = tlConfig;
31
+ if (telemetryConfig.exporter == undefined) telemetryConfig.exporter = _telemetry.inMemoryExporter;
32
+ }
33
+ if (telemetryConfig.spec) console.log(`Spec content provided`);else {
34
+ if (telemetryConfig.specFileName != "") console.log(`Spec file used for telemetry: ${telemetryConfig.specFileName}`);else {
35
+ console.log("No spec available !");
36
+ }
21
37
  }
22
38
  const router = (0, _express.Router)();
23
- const baseURL = telemetryConfig.baseURL;
24
- router.get(baseURL, landingPage);
39
+
40
+ //const baseURL = telemetryConfig.baseURL;
41
+
42
+ router.get(baseURL, mainPage);
43
+ router.get(baseURL + "/detail/*", detailPage);
44
+ router.get(baseURL + "/spec", specLoader);
45
+ router.get(baseURL + "/api", apiPage);
25
46
  router.get(baseURL + "/reset", resetTelemetry);
26
47
  router.get(baseURL + "/start", startTelemetry);
27
48
  router.get(baseURL + "/stop", stopTelemetry);
49
+ router.get(baseURL + "/status", statusTelemetry);
28
50
  router.get(baseURL + "/list", listTelemetry);
29
51
  router.post(baseURL + "/find", findTelemetry);
30
52
  router.get(baseURL + "/heapStats", heapStats);
31
53
  return router;
32
54
  }
33
- const landingPage = (req, res) => {
55
+ const apiPage = (req, res) => {
34
56
  let text = `
35
- <h1>Telemetry showcase</h1>s
36
- <h2>Available routes:</h2>
57
+ <h1>Telemetry API routes:</h1>
37
58
  <ul>
38
59
  <li><a href="/telemetry/start">/telemetry/start</a></li>
39
60
  <li><a href="/telemetry/stop">/telemetry/stop</a></li>
61
+ <li><a href="/telemetry/status">/telemetry/status</a></li>
40
62
  <li><a href="/telemetry/reset">/telemetry/reset</a></li>
41
63
  <li><a href="/telemetry/list">/telemetry/list</a></li>
42
64
  <li><a href="/telemetry/heapStats">/telemetry/heapStats</a></li>
@@ -45,14 +67,69 @@ const landingPage = (req, res) => {
45
67
  `;
46
68
  res.send(text);
47
69
  };
70
+ const mainPage = (req, res) => {
71
+ const data = (0, _fs.readFileSync)(_dirname + '/ui/main.html', {
72
+ encoding: 'utf8',
73
+ flag: 'r'
74
+ });
75
+ res.send(data);
76
+ };
77
+ const detailPage = (req, res) => {
78
+ const data = (0, _fs.readFileSync)(_dirname + '/ui/detail.html', {
79
+ encoding: 'utf8',
80
+ flag: 'r'
81
+ });
82
+ res.send(data);
83
+ };
84
+ const specLoader = (req, res) => {
85
+ if (telemetryConfig.specFileName) {
86
+ try {
87
+ const data = (0, _fs.readFileSync)(telemetryConfig.specFileName, {
88
+ encoding: 'utf8',
89
+ flag: 'r'
90
+ });
91
+ const extension = _path.default.extname(telemetryConfig.specFileName);
92
+ let json = data;
93
+ if (extension == _jsYaml.default) json = JSON.stringify(_jsYaml.default.SafeLoad(data), null, 2);
94
+ res.setHeader('Content-Type', 'application/json');
95
+ res.send(json);
96
+ } catch (e) {
97
+ console.log(`ERROR loading spec file ${telemetryConfig.specFileName}: ${e}`);
98
+ }
99
+ } else {
100
+ if (telemetryConfig.spec) {
101
+ let spec = false;
102
+ try {
103
+ spec = JSON.parse(telemetryConfig.spec);
104
+ } catch (ej) {
105
+ try {
106
+ spec = JSON.stringify(_jsYaml.default.load(telemetryConfig.spec), null, 2);
107
+ } catch (ey) {
108
+ console.log(`Error parsing spec: ${ej} - ${ey}`);
109
+ }
110
+ }
111
+ if (!spec) {
112
+ res.status(404);
113
+ } else {
114
+ res.setHeader('Content-Type', 'application/json');
115
+ res.send(spec);
116
+ }
117
+ }
118
+ }
119
+ };
48
120
  const startTelemetry = (req, res) => {
49
121
  telemetryConfig.exporter.start();
122
+ telemetryStatus.active = true;
50
123
  res.send('Telemetry started');
51
124
  };
52
125
  const stopTelemetry = (req, res) => {
53
126
  telemetryConfig.exporter.stop();
127
+ telemetryStatus.active = false;
54
128
  res.send('Telemetry stopped');
55
129
  };
130
+ const statusTelemetry = (req, res) => {
131
+ res.send(telemetryStatus);
132
+ };
56
133
  const resetTelemetry = (req, res) => {
57
134
  telemetryConfig.exporter.reset();
58
135
  res.send('Telemetry reset');
package/package.json CHANGED
@@ -1,46 +1,51 @@
1
- {
2
- "name": "@oas-tools/oas-telemetry",
3
- "version": "0.1.5",
4
- "description": "This package exports an express midelware that allows to trace the requests and responses of an express application using OpenTelemetry",
5
- "author": "Manuel Otero",
6
- "contributors": [
7
- "Alejandro Santisteban"
8
- ],
9
- "license": "Apache-2.0",
10
- "type": "module",
11
- "scripts": {
12
- "build": "babel src -d dist --out-file-extension .cjs",
13
- "publish": "npm run build && npm publish"
14
- },
15
- "files": [
16
- "dist",
17
- "src"
18
- ],
19
- "main": "./dist/index.cjs",
20
- "module": "./src/index.js",
21
- "exports": {
22
- "require": "./dist/index.cjs",
23
- "import": "./src/index.js",
24
- "default": "./src/index.js"
25
- },
26
- "dependencies": {
27
- "@opentelemetry/instrumentation-http": "^0.51.0",
28
- "@opentelemetry/resources": "^1.24.0",
29
- "@opentelemetry/sdk-node": "^0.49.1",
30
- "express": "^4.19.2",
31
- "nedb": "^1.8.0",
32
- "v8": "^0.1.0"
33
- },
34
- "devDependencies": {
35
- "@babel/cli": "^7.24.1",
36
- "@babel/core": "^7.24.4",
37
- "@babel/plugin-proposal-class-properties": "^7.18.6",
38
- "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
39
- "@babel/preset-env": "^7.24.4",
40
- "@opentelemetry/api": "^1.8.0",
41
- "@opentelemetry/auto-instrumentations-node": "^0.43.0",
42
- "babel-plugin-add-module-exports": "^1.0.4",
43
- "babel-plugin-module-extension": "^0.1.3",
44
- "nodemon": "^3.1.0"
45
- }
46
- }
1
+ {
2
+ "name": "@oas-tools/oas-telemetry",
3
+ "version": "0.1.6",
4
+ "description": "This package exports an express midelware that allows to trace the requests and responses of an express application using OpenTelemetry",
5
+ "author": "Manuel Otero",
6
+ "contributors": [
7
+ "Alejandro Santisteban","Pablo Fernandez"
8
+ ],
9
+ "license": "Apache-2.0",
10
+ "type": "module",
11
+ "scripts": {
12
+ "build": "babel src -d dist --out-file-extension .cjs",
13
+ "publish": "npm run build && npm publish",
14
+ "test": "npm i && cd test/performance/ && ./test.sh"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src"
19
+ ],
20
+ "main": "./dist/index.cjs",
21
+ "module": "./src/index.js",
22
+ "exports": {
23
+ "require": "./dist/index.cjs",
24
+ "import": "./src/index.js",
25
+ "default": "./src/index.js"
26
+ },
27
+ "dependencies": {
28
+ "@opentelemetry/instrumentation-http": "^0.51.0",
29
+ "@opentelemetry/resources": "^1.24.0",
30
+ "@opentelemetry/sdk-node": "^0.49.1",
31
+ "axios": "^1.6.8",
32
+ "express": "^4.19.2",
33
+ "js-yaml": "^4.1.0",
34
+ "nedb": "^1.8.0",
35
+ "readline": "^1.3.0",
36
+ "v8": "^0.1.0"
37
+ },
38
+ "devDependencies": {
39
+ "@babel/cli": "^7.24.1",
40
+ "@babel/core": "^7.24.4",
41
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
42
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
43
+ "@babel/preset-env": "^7.24.4",
44
+ "@opentelemetry/api": "^1.8.0",
45
+ "@opentelemetry/auto-instrumentations-node": "^0.43.0",
46
+ "apipecker": "^1.3.1",
47
+ "babel-plugin-add-module-exports": "^1.0.4",
48
+ "babel-plugin-module-extension": "^0.1.3",
49
+ "nodemon": "^3.1.0"
50
+ }
51
+ }
@@ -1,90 +1,90 @@
1
- import { ExportResultCode } from '@opentelemetry/core';
2
-
3
- //import in memory database
4
- import dataStore from 'nedb'
5
-
6
- export class InMemoryExporter {
7
- constructor() {
8
- this._spans = new dataStore();
9
- this._stopped = false;
10
- }
11
- export(readableSpans, resultCallback) {
12
- try {
13
- if (!this._stopped) {
14
- // Remove circular references
15
- const cleanSpans = readableSpans.map(span => removeCircular(span));
16
-
17
- // Insert spans into the in-memory database
18
- this._spans.insert(cleanSpans, (err, newDoc) => {
19
- if (err) {
20
- console.error(err);
21
- return;
22
- }
23
- });
24
-
25
- }
26
- setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
27
- } catch (error) {
28
- console.error('Error exporting spans\n' + error.message + '\n' + error.stack);
29
- return resultCallback({
30
- code: ExportResultCode.FAILED,
31
- error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack),
32
- })
33
- }
34
- }
35
- start() {
36
- this._stopped = false;
37
- }
38
- stop() {
39
- this._stopped = true;
40
- }
41
- shutdown() {
42
- this._stopped = true;
43
- this._spans = new dataStore();
44
- return this.forceFlush();
45
- }
46
- /**
47
- * Exports any pending spans in the exporter
48
- */
49
- forceFlush() {
50
- return Promise.resolve();
51
- }
52
- reset() {
53
- this._spans = new dataStore();
54
- }
55
- getFinishedSpans() {
56
- return this._spans;
57
- }
58
- }
59
-
60
- function removeCircular(obj) {
61
- const seen = new WeakMap(); // Used to keep track of visited objects
62
-
63
-
64
- // Replacer function to handle circular references
65
- function replacer(key, value) {
66
- if (key === "_spanProcessor") {
67
- return "oas-telemetry skips this field to avoid circular reference";
68
- }
69
- // GENERIC CIRCULAR REFERENCE HANDLING
70
- // if (typeof value === "object" && value !== null) {
71
- // // If the object has been visited before, return the name prefixed with "CIRCULAR+"
72
- // if (seen.has(value)) {
73
- // return `CIRCULAR${key}`;
74
- // }
75
- // seen.set(value, key); // Mark the object as visited with its name
76
- // }
77
- return value;
78
- }
79
-
80
- // Convert the object to a string and then parse it back
81
- // This will trigger the replacer function to handle circular references
82
- const jsonString = JSON.stringify(obj, replacer);
83
- const spanNoDotsInKeys =jsonString.replace(/[^"]*":/g, (match) => {
84
- // Replace all dots in the key with underscores (e.g. "http.method" -> "http_method")
85
- const newMatch = match.replace(/\./g,"_dot_")
86
-
87
- return newMatch
88
- })
89
- return JSON.parse(spanNoDotsInKeys);
1
+ import { ExportResultCode } from '@opentelemetry/core';
2
+
3
+ //import in memory database
4
+ import dataStore from 'nedb'
5
+
6
+ export class InMemoryExporter {
7
+ constructor() {
8
+ this._spans = new dataStore();
9
+ this._stopped = false;
10
+ }
11
+ export(readableSpans, resultCallback) {
12
+ try {
13
+ if (!this._stopped) {
14
+ // Remove circular references
15
+ const cleanSpans = readableSpans.map(span => removeCircular(span));
16
+
17
+ // Insert spans into the in-memory database
18
+ this._spans.insert(cleanSpans, (err, newDoc) => {
19
+ if (err) {
20
+ console.error(err);
21
+ return;
22
+ }
23
+ });
24
+
25
+ }
26
+ setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
27
+ } catch (error) {
28
+ console.error('Error exporting spans\n' + error.message + '\n' + error.stack);
29
+ return resultCallback({
30
+ code: ExportResultCode.FAILED,
31
+ error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack),
32
+ })
33
+ }
34
+ }
35
+ start() {
36
+ this._stopped = false;
37
+ }
38
+ stop() {
39
+ this._stopped = true;
40
+ }
41
+ shutdown() {
42
+ this._stopped = true;
43
+ this._spans = new dataStore();
44
+ return this.forceFlush();
45
+ }
46
+ /**
47
+ * Exports any pending spans in the exporter
48
+ */
49
+ forceFlush() {
50
+ return Promise.resolve();
51
+ }
52
+ reset() {
53
+ this._spans = new dataStore();
54
+ }
55
+ getFinishedSpans() {
56
+ return this._spans;
57
+ }
58
+ }
59
+
60
+ function removeCircular(obj) {
61
+ const seen = new WeakMap(); // Used to keep track of visited objects
62
+
63
+
64
+ // Replacer function to handle circular references
65
+ function replacer(key, value) {
66
+ if (key === "_spanProcessor") {
67
+ return "oas-telemetry skips this field to avoid circular reference";
68
+ }
69
+ // GENERIC CIRCULAR REFERENCE HANDLING
70
+ // if (typeof value === "object" && value !== null) {
71
+ // // If the object has been visited before, return the name prefixed with "CIRCULAR+"
72
+ // if (seen.has(value)) {
73
+ // return `CIRCULAR${key}`;
74
+ // }
75
+ // seen.set(value, key); // Mark the object as visited with its name
76
+ // }
77
+ return value;
78
+ }
79
+
80
+ // Convert the object to a string and then parse it back
81
+ // This will trigger the replacer function to handle circular references
82
+ const jsonString = JSON.stringify(obj, replacer);
83
+ const spanNoDotsInKeys =jsonString.replace(/[^"]*":/g, (match) => {
84
+ // Replace all dots in the key with underscores (e.g. "http.method" -> "http_method")
85
+ const newMatch = match.replace(/\./g,"_dot_")
86
+
87
+ return newMatch
88
+ })
89
+ return JSON.parse(spanNoDotsInKeys);
90
90
  }