ntlogger 2.5.2 → 2.6.0
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/index.js +4 -1
- package/package.json +3 -2
- package/plugins/README.md +137 -5
- package/plugins/discord.js +1 -1
- package/plugins/index.js +1 -0
- package/plugins/teams.js +311 -0
package/index.js
CHANGED
|
@@ -8,11 +8,14 @@
|
|
|
8
8
|
* TODO: [Feature] Generic Webhook Plugin for sending logs to any webhook
|
|
9
9
|
* TODO: [Feature] Email Plugin for sending logs to an email address
|
|
10
10
|
* TODO: [Feature] SMS Mail ID Plugin for sending logs to a phone number
|
|
11
|
+
* TODO: [Feature] Allow for custom log levels and colors
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Change Log:
|
|
15
|
-
*
|
|
16
|
+
* v2.6.0 - 08/15/2024:
|
|
17
|
+
* [FEATURE] Teams Plugin! Send logs to a Microsoft Teams channel using incoming webhooks.
|
|
18
|
+
*
|
|
16
19
|
* v2.5.2 - 08/11/2024:
|
|
17
20
|
* [BUG] Fixed an issue where the /plugins/lib folder was not being pushed to npmjs.com.
|
|
18
21
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ntlogger",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/NightSquawk/NightTimeLogger.git"
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"sentry compatible",
|
|
21
21
|
"mysql compatible",
|
|
22
22
|
"syslog compatible",
|
|
23
|
-
"discord compatible"
|
|
23
|
+
"discord compatible",
|
|
24
|
+
"teams compatible"
|
|
24
25
|
],
|
|
25
26
|
"files": [
|
|
26
27
|
"index.js",
|
package/plugins/README.md
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
NightTimeLogger is a powerful and flexible logging utility with various plugins to extend its functionality. This README provides an overview of the available plugins and instructions on how to set them up.
|
|
4
4
|
|
|
5
|
-

|
|
6
|
-
|
|
7
5
|
## Available Plugins
|
|
8
6
|
|
|
9
7
|
### 1. Discord
|
|
10
8
|
**Description:** Sends logs to a Discord webhook, allowing you to receive log messages directly in a specified Discord channel.
|
|
11
9
|
|
|
10
|
+

|
|
11
|
+
|
|
12
12
|
**Setup:**
|
|
13
13
|
```javascript
|
|
14
14
|
{
|
|
15
15
|
name: 'Discord',
|
|
16
16
|
config: {
|
|
17
|
-
webhookUrl: process.env.DISCORD_WEBHOOK_URL
|
|
17
|
+
webhookUrl: process.env.DISCORD_WEBHOOK_URL
|
|
18
18
|
avatarUrl: process.env.DISCORD_AVATAR_URL || 'https://pbs.twimg.com/profile_images/997535493624508416/V7Ed1k2o_400x400.jpg',
|
|
19
19
|
username: process.env.DISCORD_USERNAME || 'NTLogger - Info',
|
|
20
20
|
level: "info",
|
|
@@ -51,7 +51,7 @@ Setup:
|
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
### . MySQL
|
|
54
|
+
### 3. MySQL
|
|
55
55
|
Description: Stores logs in a MySQL database, allowing you to persist log messages and analyze them using SQL queries.
|
|
56
56
|
|
|
57
57
|
Setup:
|
|
@@ -84,6 +84,9 @@ Setup:
|
|
|
84
84
|
### 5. Syslog
|
|
85
85
|
Description: Sends logs to a Syslog server using a custom Syslog client. This allows integration with traditional logging systems that rely on Syslog.
|
|
86
86
|
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
|
|
87
90
|
Setup:
|
|
88
91
|
|
|
89
92
|
``` javascript
|
|
@@ -101,11 +104,140 @@ Setup:
|
|
|
101
104
|
}
|
|
102
105
|
```
|
|
103
106
|
|
|
107
|
+
### 6. Teams
|
|
108
|
+
**Description:** Sends logs to a Microsoft Teams channel using an incoming webhook connector. This plugin allows you to receive log messages directly in a specified Teams channel.
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+

|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
**Setup:**
|
|
115
|
+
|
|
116
|
+
``` javascript
|
|
117
|
+
{
|
|
118
|
+
name: 'Teams',
|
|
119
|
+
config: {
|
|
120
|
+
webhookUrl: process.env.TEAMS_WEBHOOK_URL || "im not leaking my webhook url again",
|
|
121
|
+
level: process.env.LOG_LEVEL || "info",
|
|
122
|
+
strict: process.env.LOG_STRICT_LOGGING || true,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This plugin supports additional configuration at the meta level. This allows you to create complex Teams messages with custom formatting and attachments..
|
|
128
|
+
|
|
129
|
+

|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
log.info('Informational message', [
|
|
133
|
+
{ type: "location", district: "District 1", store: "Store 1", department: "Department 1"},
|
|
134
|
+
{ type: "button", actionableBoxName: "First Button!", actionableURL: 'firstURL' },
|
|
135
|
+
{ type: "button", actionableBoxName: "Second Button!", actionableURL: 'secondURL' },
|
|
136
|
+
// { type: "ping", mentionId: "example@example.com"}, // MUST BE A VALID USER EMAIL
|
|
137
|
+
// { type: "ping", mentionId: "example@example.com"}, // MUST BE A VALID USER EMAIL
|
|
138
|
+
{ "type": "error", "message": "An unexpected error occurred.", "stack": "Error stack trace here" },
|
|
139
|
+
{ "type": "metric", "name": "CPU Usage", "value": "85%" },
|
|
140
|
+
{ "type": "metric", "name": "Request Count", "value": 123 },
|
|
141
|
+
]);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
It also supports the complete https://adaptivecards.io/explorer/AdaptiveCard.html schema.
|
|
145
|
+
|
|
146
|
+

|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
log.error('Error message',[
|
|
150
|
+
{ type: "raw", raw: {
|
|
151
|
+
body: [
|
|
152
|
+
{ type: "TextBlock", text: "Raw Type" },
|
|
153
|
+
{
|
|
154
|
+
type: "ColumnSet",
|
|
155
|
+
columns: [
|
|
156
|
+
{ type: "Column",
|
|
157
|
+
items: [
|
|
158
|
+
{ "type": "TextBlock", "text": "Cats" },
|
|
159
|
+
{ type: "Image",url: "https://png.pngtree.com/png-clipart/20230511/ourmid/pngtree-isolated-cat-on-white-background-png-image_7094927.png", altText: "Cat", wrap: true, size: "auto", separator: true, },
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{ type: "Column",
|
|
163
|
+
items: [
|
|
164
|
+
{ "type": "TextBlock", "text": "Dogs" },
|
|
165
|
+
{ type: "Image",url: "https://i.pinimg.com/originals/07/b2/40/07b240561cb656aec289df602e603bee.png", altText: "Dog", wrap: true, size: "auto", separator: true, },
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{ type: "Column",
|
|
169
|
+
items: [
|
|
170
|
+
{ "type": "TextBlock", "text": "Birds" },
|
|
171
|
+
{ type: "Image",url: "https://cdn.pixabay.com/photo/2016/03/02/13/59/bird-1232416_1280.png", altText: "Bird", wrap: true, size: "auto", separator: true, }
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"type": "FactSet",
|
|
178
|
+
"facts": [
|
|
179
|
+
{
|
|
180
|
+
"title": "Fact 1",
|
|
181
|
+
"value": "Value 1"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"title": "Fact 2",
|
|
185
|
+
"value": "Value 2"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"title": "Fact 3",
|
|
189
|
+
"value": "Value 3"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"title": "Fact 4",
|
|
193
|
+
"value": "Value 5"
|
|
194
|
+
}
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
action: [
|
|
199
|
+
{
|
|
200
|
+
type: 'Action.OpenUrl',
|
|
201
|
+
title: "See more cats!",
|
|
202
|
+
url: 'https://www.google.com/search?q=cute%20cats&udm=2'
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'Action.OpenUrl',
|
|
206
|
+
title: "Chickens?",
|
|
207
|
+
url: 'https://www.google.com/search?q=chickens&udm=2'
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"type": "Action.ShowCard",
|
|
211
|
+
"title": "Whats this?",
|
|
212
|
+
"card": {
|
|
213
|
+
"type": "AdaptiveCard",
|
|
214
|
+
"body": [
|
|
215
|
+
{
|
|
216
|
+
"type": "TextBlock",
|
|
217
|
+
"text": "Cool?"
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
"actions": [
|
|
221
|
+
{
|
|
222
|
+
"type": "Action.Submit",
|
|
223
|
+
"title": "You betcha!",
|
|
224
|
+
"data": {
|
|
225
|
+
"betcha": "true"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
]},
|
|
232
|
+
},
|
|
233
|
+
]);
|
|
234
|
+
```
|
|
235
|
+
|
|
104
236
|
### Example Logger Configuration
|
|
105
237
|
Here is an example configuration for NightTimeLogger using multiple plugins:
|
|
106
238
|
|
|
107
239
|
``` javascript
|
|
108
|
-
|
|
240
|
+
|
|
109
241
|
let config = {
|
|
110
242
|
level: 'internal',
|
|
111
243
|
file: false,
|
package/plugins/discord.js
CHANGED
|
@@ -8,7 +8,7 @@ const https = require('https');
|
|
|
8
8
|
const { URL } = require('url');
|
|
9
9
|
|
|
10
10
|
const colors = require('../lib/colors');
|
|
11
|
-
const levels = require('../lib/levels');
|
|
11
|
+
const levels = require('../lib/levels');
|
|
12
12
|
|
|
13
13
|
class DiscordTransport extends Transport {
|
|
14
14
|
constructor(opts = {}) {
|
package/plugins/index.js
CHANGED
package/plugins/teams.js
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file /plugins/teams.js
|
|
3
|
+
* @description Sends logs to a Teams webhook.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const Transport = require('winston-transport');
|
|
7
|
+
const https = require('https');
|
|
8
|
+
const { URL } = require('url');
|
|
9
|
+
|
|
10
|
+
const levels = require('../lib/levels');
|
|
11
|
+
|
|
12
|
+
class TeamsTransport extends Transport {
|
|
13
|
+
constructor(opts = {}) {
|
|
14
|
+
super(opts);
|
|
15
|
+
|
|
16
|
+
this.name = 'Teams Webhook Transport for NTLogger';
|
|
17
|
+
|
|
18
|
+
this.webhookUrl = opts.webhookUrl;
|
|
19
|
+
this.strict = opts.strict || false;
|
|
20
|
+
|
|
21
|
+
// Retry logic with exponential back-off
|
|
22
|
+
// https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL%2Ctext1#rate-limiting-for-connectors
|
|
23
|
+
this.maxRetries = opts.maxRetries || 3;
|
|
24
|
+
this.retryDelay = opts.retryDelay || 1000; // Initial delay for exponential back-off (in ms)
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Set the log level
|
|
28
|
+
this.level = opts.level || 'info';
|
|
29
|
+
if (!(this.level in levels)) {
|
|
30
|
+
throw new Error(`Invalid log level: ${this.level}`);
|
|
31
|
+
}
|
|
32
|
+
this.levelPriority = levels[this.level]; // Get the numerical priority of the log level
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`Error setting log level: ${error.message}`);
|
|
35
|
+
console.error(error.stack);
|
|
36
|
+
throw error; // Rethrow the error to stop the transport creation if level is invalid
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async log(info, callback) {
|
|
41
|
+
setImmediate(() => {
|
|
42
|
+
this.emit('logged', info);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const { level, message, ...meta } = info;
|
|
46
|
+
|
|
47
|
+
// Check if the log level matches the configured level (strict mode) or is at or below the configured level
|
|
48
|
+
if (this.strict) {
|
|
49
|
+
if (level !== this.level) {
|
|
50
|
+
callback(); // Skip sending the log if it's not exactly the configured level
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
if (levels[level] > this.levelPriority) {
|
|
55
|
+
callback(); // Skip sending the log if it's above the configured level
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const payload = this.createPayload(level, message, meta);
|
|
61
|
+
const webhookUrl = new URL(this.webhookUrl);
|
|
62
|
+
|
|
63
|
+
const options = {
|
|
64
|
+
hostname: webhookUrl.hostname,
|
|
65
|
+
path: webhookUrl.pathname + webhookUrl.search,
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
'Content-Length': Buffer.byteLength(payload),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const sendLog = (retryCount = 0) => {
|
|
74
|
+
const req = https.request(options, (res) => {
|
|
75
|
+
let responseContent = '';
|
|
76
|
+
|
|
77
|
+
res.on('data', (chunk) => {
|
|
78
|
+
responseContent += chunk;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
res.on('end', () => {
|
|
82
|
+
if (responseContent.includes("Microsoft Teams endpoint returned HTTP error 429")) {
|
|
83
|
+
console.error('Rate limit hit, retrying with exponential back-off...');
|
|
84
|
+
if (retryCount < this.maxRetries) {
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
sendLog(retryCount + 1);
|
|
87
|
+
}, this.retryDelay * Math.pow(2, retryCount)); // Exponential back-off
|
|
88
|
+
} else {
|
|
89
|
+
console.error('Max retries reached, log sending failed.');
|
|
90
|
+
callback();
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
callback();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
req.on('error', (e) => {
|
|
99
|
+
console.error(`Failed to send log to Teams: ${e.message}`);
|
|
100
|
+
if (retryCount < this.maxRetries) {
|
|
101
|
+
console.log(`Retrying... (${retryCount + 1}/${this.maxRetries})`);
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
sendLog(retryCount + 1);
|
|
104
|
+
}, this.retryDelay * Math.pow(2, retryCount));
|
|
105
|
+
} else {
|
|
106
|
+
console.error('Max retries reached, log sending failed.');
|
|
107
|
+
callback();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
req.write(payload);
|
|
112
|
+
req.end();
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
sendLog();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
createPayload(level, message, meta) {
|
|
119
|
+
const actions = [];
|
|
120
|
+
const body = [
|
|
121
|
+
{
|
|
122
|
+
type: 'TextBlock',
|
|
123
|
+
text: `Log Level: ${level.toUpperCase()} - ${message}`,
|
|
124
|
+
weight: 'Bolder',
|
|
125
|
+
size: 'Medium'
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
const mentions = [];
|
|
129
|
+
let mentionTextAdded = false; // Track if the mention text block has been added
|
|
130
|
+
|
|
131
|
+
// Ensure meta is treated as an array
|
|
132
|
+
const metaArray = Array.isArray(meta) ? meta : Object.values(meta);
|
|
133
|
+
|
|
134
|
+
metaArray.forEach(item => {
|
|
135
|
+
if (typeof item !== 'object' || !item.type) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
switch (item.type) {
|
|
140
|
+
case 'raw':
|
|
141
|
+
if (item.raw && Array.isArray(item.raw.body)) {
|
|
142
|
+
body.push(...item.raw.body);
|
|
143
|
+
}
|
|
144
|
+
if (item.raw && Array.isArray(item.raw.action)) {
|
|
145
|
+
actions.push(...item.raw.action);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
|
|
149
|
+
case 'location':
|
|
150
|
+
body.push({
|
|
151
|
+
type: 'FactSet',
|
|
152
|
+
facts: [
|
|
153
|
+
{ title: "District", value: item.district || "N/A" },
|
|
154
|
+
{ title: "Store", value: item.store || "N/A" },
|
|
155
|
+
{ title: "Department", value: item.department || "N/A" }
|
|
156
|
+
]
|
|
157
|
+
});
|
|
158
|
+
break;
|
|
159
|
+
|
|
160
|
+
case 'button':
|
|
161
|
+
actions.push({
|
|
162
|
+
type: 'Action.OpenUrl',
|
|
163
|
+
title: item.actionableBoxName || "Button",
|
|
164
|
+
url: item.actionableURL || '#'
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
|
|
168
|
+
case 'ping':
|
|
169
|
+
if (!mentionTextAdded) {
|
|
170
|
+
body.push({
|
|
171
|
+
type: 'Container',
|
|
172
|
+
items: [
|
|
173
|
+
{
|
|
174
|
+
type: 'TextBlock',
|
|
175
|
+
text: `<at>${item.mentionId}</at>`,
|
|
176
|
+
wrap: true
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
});
|
|
180
|
+
mentionTextAdded = true;
|
|
181
|
+
}
|
|
182
|
+
mentions.push({
|
|
183
|
+
type: 'mention',
|
|
184
|
+
text: `<at>${item.mentionId}</at>`,
|
|
185
|
+
mentioned: {
|
|
186
|
+
id: item.mentionId
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
case 'error':
|
|
192
|
+
body.push({
|
|
193
|
+
type: 'TextBlock',
|
|
194
|
+
text: `Error: ${item.message || "No message"}`,
|
|
195
|
+
weight: 'Bolder',
|
|
196
|
+
color: 'Attention',
|
|
197
|
+
wrap: true
|
|
198
|
+
});
|
|
199
|
+
if (item.stack) {
|
|
200
|
+
body.push({
|
|
201
|
+
type: 'TextBlock',
|
|
202
|
+
text: `Stack Trace: ${item.stack}`,
|
|
203
|
+
color: 'Attention',
|
|
204
|
+
wrap: true
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
|
|
209
|
+
case 'metric':
|
|
210
|
+
body.push({
|
|
211
|
+
type: 'FactSet',
|
|
212
|
+
facts: [
|
|
213
|
+
{ title: item.name || "Metric", value: item.value || "N/A" }
|
|
214
|
+
]
|
|
215
|
+
});
|
|
216
|
+
break;
|
|
217
|
+
|
|
218
|
+
case 'ColumnSet':
|
|
219
|
+
if (item.complexity === 'complex') {
|
|
220
|
+
const columns = item.table[0].map((header, colIndex) => ({
|
|
221
|
+
type: 'Column',
|
|
222
|
+
items: [
|
|
223
|
+
{
|
|
224
|
+
type: 'TextBlock',
|
|
225
|
+
text: header.text || header,
|
|
226
|
+
weight: 'Bolder',
|
|
227
|
+
separator: true,
|
|
228
|
+
wrap: true
|
|
229
|
+
},
|
|
230
|
+
...item.table.slice(1).map(row => {
|
|
231
|
+
return row[colIndex]
|
|
232
|
+
})
|
|
233
|
+
],
|
|
234
|
+
width: 'auto'
|
|
235
|
+
}));
|
|
236
|
+
|
|
237
|
+
const columnSet = {
|
|
238
|
+
type: 'ColumnSet',
|
|
239
|
+
separator: true,
|
|
240
|
+
columns: columns
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
body.push(columnSet);
|
|
244
|
+
break;
|
|
245
|
+
} else {
|
|
246
|
+
const columns = item.table[0].map((header, colIndex) => ({
|
|
247
|
+
type: 'Column',
|
|
248
|
+
items: [
|
|
249
|
+
{
|
|
250
|
+
type: 'TextBlock',
|
|
251
|
+
text: header,
|
|
252
|
+
weight: 'Bolder',
|
|
253
|
+
separator: true,
|
|
254
|
+
wrap: true
|
|
255
|
+
},
|
|
256
|
+
...item.table.slice(1).map(row => ({
|
|
257
|
+
type: 'TextBlock',
|
|
258
|
+
text: row[colIndex],
|
|
259
|
+
separator: true,
|
|
260
|
+
wrap: true
|
|
261
|
+
}))
|
|
262
|
+
],
|
|
263
|
+
width: 'auto'
|
|
264
|
+
}));
|
|
265
|
+
|
|
266
|
+
const columnSet = {
|
|
267
|
+
type: 'ColumnSet',
|
|
268
|
+
separator: true,
|
|
269
|
+
columns: columns
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
body.push(columnSet);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
|
|
277
|
+
default:
|
|
278
|
+
body.push({
|
|
279
|
+
type: 'TextBlock',
|
|
280
|
+
text: `Unsupported type: ${item.type}`,
|
|
281
|
+
color: 'Warning',
|
|
282
|
+
wrap: true
|
|
283
|
+
});
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
return JSON.stringify({
|
|
289
|
+
type: 'message',
|
|
290
|
+
attachments: [
|
|
291
|
+
{
|
|
292
|
+
summary: `Log Level: ${level.toUpperCase()} - ${message}`,
|
|
293
|
+
contentType: 'application/vnd.microsoft.card.adaptive',
|
|
294
|
+
content: {
|
|
295
|
+
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
|
|
296
|
+
version: '1.2',
|
|
297
|
+
msteams: {
|
|
298
|
+
entities: mentions
|
|
299
|
+
},
|
|
300
|
+
body: body,
|
|
301
|
+
actions: actions
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
module.exports = {
|
|
310
|
+
transport: TeamsTransport,
|
|
311
|
+
};
|