Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

errsole

Package Overview
Dependencies
Maintainers
1
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

errsole - npm Package Compare versions

Comparing version 2.3.0 to 2.4.0

18

lib/errsole.js
'use strict';
const { createProxyMiddleware } = require('http-proxy-middleware');
const ErrsoleMain = require('./main');
const Errsole = {};
const Errsole = {
port: 8001
};
Errsole.initialize = function (options) {
if (!options) {
throw new Error('Initialization failed');
}
Errsole.initialize = function (options = {}) {
if (!options.storage) {
throw new Error('Initialization failed: "storage" property is missing.');
}
this.port = parseInt(options.port, 10) || 8001;
ErrsoleMain.initialize(options);

@@ -59,2 +60,9 @@ };

Errsole.proxyMiddleware = function () {
return createProxyMiddleware({
target: 'http://localhost:' + this.port,
changeOrigin: true
});
};
module.exports = Errsole;
'use strict';
const os = require('os');
const Logs = require('./logs');

@@ -7,39 +8,74 @@ const ExpressApp = require('./server');

const Main = {};
const Main = {
appName: null,
environmentName: process.env.NODE_ENV || null,
serverName: null,
Main.initialize = function (options) {
const port = parseInt(options.port) || 8001;
Logs.initialize(options);
const enableDashboard = typeof options.enableDashboard === 'boolean' ? options.enableDashboard : true;
const exitOnException = typeof options.exitOnException === 'boolean' ? options.exitOnException : true;
if (enableDashboard) {
ExpressApp.addStorage(options);
ExpressApp.addPath(options);
ExpressApp.listen(port, () => {
const basePath = options.path || '';
console.log('Errsole Dashboard is accessible at http://localhost:' + port + basePath);
initialize (options) {
this.loadPackageInfo();
this.setupConfiguration(options);
Logs.initialize(options);
this.startServer(options);
this.handleUncaughtExceptions(options.exitOnException);
},
loadPackageInfo () {
try {
this.serverName = os.hostname() || null;
const packageJSON = require('../../../../package.json');
this.appName = packageJSON.name || null;
} catch (err) {
}
},
setupConfiguration (options) {
this.appName = options.appName || this.appName;
this.environmentName = options.environmentName || this.environmentName;
this.serverName = options.serverName || this.serverName;
options.port = parseInt(options.port, 10) || 8001;
options.enableDashboard = typeof options.enableDashboard === 'boolean' ? options.enableDashboard : true;
options.exitOnException = typeof options.exitOnException === 'boolean' ? options.exitOnException : true;
},
startServer (options) {
if (options.enableDashboard) {
ExpressApp.addStorage(options);
ExpressApp.addPath(options);
ExpressApp.listen(options.port, () => {
const basePath = options.path || '';
console.log(`Errsole Dashboard is accessible at http://localhost:${options.port}${basePath}`);
});
} else {
console.log('Errsole Dashboard is disabled: You have disabled the Errsole Dashboard in the Errsole module configuration.');
}
},
async customLogger (level, message, metadata) {
Logs.customLogger(level, message, metadata);
if (level === 'alert') {
const messageExtraInfo = {
appName: this.appName,
environmentName: this.environmentName,
serverName: this.serverName
};
await Alerts.customLoggerAlert(message, messageExtraInfo);
}
},
async handleUncaughtExceptions (exitOnException) {
process.on('uncaughtException', async (err, origin) => {
const errorOrigin = `Origin: ${origin}`;
const errorMessage = err.stack || err.message;
console.error(`${errorOrigin}\n${errorMessage}`);
const messageExtraInfo = {
appName: this.appName,
environmentName: this.environmentName,
serverName: this.serverName
};
await Alerts.handleUncaughtExceptions(`${errorOrigin}\n${errorMessage}`, messageExtraInfo);
if (exitOnException) process.exit(1);
});
} else {
console.log('Errsole Dashboard is disabled: You have disabled the Errsole Dashboard in the Errsole module configuration.');
}
handleUncaughtExceptions(exitOnException);
};
Main.customLogger = async function (level, message, metadata) {
Logs.customLogger(level, message, metadata);
if (level === 'alert') {
await Alerts.customLoggerAlert(message);
}
};
async function handleUncaughtExceptions (exitOnException) {
process.on('uncaughtException', async function (err, origin) {
const errorOrigin = 'Origin: ' + origin;
const errorMessage = err.stack || err.message;
console.error(`${errorOrigin}\n${errorMessage}`);
await Alerts.handleUncaughtExceptions(errorOrigin + '\n' + errorMessage);
if (exitOnException) process.exit(1);
});
}
module.exports = Main;

@@ -14,3 +14,3 @@ const stream = require('stream');

collectLogs: [],
hostname: os.hostname(),
hostname: null,
pid,

@@ -22,2 +22,3 @@ enableConsoleOutput: true

this.storage = options.storage;
this.hostname = options.serverName || os.hostname();
if (options && typeof options.enableConsoleOutput !== 'undefined') {

@@ -24,0 +25,0 @@ this.enableConsoleOutput = options.enableConsoleOutput;

@@ -32,3 +32,3 @@ const Jsonapi = require('../utils/jsonapiUtil');

exports.getSlack = async (req, res) => {
exports.getSlackDetails = async (req, res) => {
try {

@@ -53,3 +53,3 @@ const storageConnection = getStorageConnection();

exports.addSlack = async (req, res) => {
exports.addSlackDetails = async (req, res) => {
try {

@@ -63,3 +63,4 @@ const { url } = helpers.extractAttributes(req.body);

username: 'Errsole',
icon_url: 'https://avatars.githubusercontent.com/u/84983840'
icon_url: 'https://avatars.githubusercontent.com/u/84983840',
status: true
};

@@ -96,3 +97,3 @@ const result = await storageConnection.setConfig('slackIntegration', JSON.stringify(details));

exports.updateSlack = async (req, res) => {
exports.updateSlackDetails = async (req, res) => {
try {

@@ -148,3 +149,3 @@ const { status } = helpers.extractAttributes(req.body);

exports.deleteSlack = async (req, res) => {
exports.deleteSlackDetails = async (req, res) => {
try {

@@ -174,1 +175,134 @@ const { url } = helpers.extractAttributes(req.body);

};
exports.getEmailDetails = async (req, res) => {
try {
const storageConnection = getStorageConnection();
const data = await storageConnection.getConfig('emailIntegration');
if (data && data.item) {
data.item.value = JSON.parse(data.item.value);
delete data.item.value.url;
}
res.send(Jsonapi.Serializer.serialize(Jsonapi.AppType, data.item || {}));
} catch (error) {
console.error(error);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
};
exports.addEmailDetails = async (req, res) => {
try {
const { sender, host, port, username, password, receivers } = helpers.extractAttributes(req.body);
const storageConnection = getStorageConnection();
const details = {
sender,
host,
port,
username,
password,
receivers,
status: true
};
const result = await storageConnection.setConfig('emailIntegration', JSON.stringify(details));
if (result && result.item) {
result.item.value = JSON.parse(result.item.value);
res.send(Jsonapi.Serializer.serialize(Jsonapi.AppType, result.item));
} else {
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
} catch (error) {
console.error(error);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
};
exports.updateEmailDetails = async (req, res) => {
try {
const { status } = helpers.extractAttributes(req.body);
const storageConnection = getStorageConnection();
const data = await storageConnection.getConfig('emailIntegration');
if (data && data.item) {
let parsedValue;
try {
parsedValue = JSON.parse(data.item.value);
parsedValue.status = status;
} catch (err) {
console.error(err);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
data.item.value.status = status;
const result = await storageConnection.setConfig('emailIntegration', JSON.stringify(parsedValue));
if (result && result.item) {
result.item.value = JSON.parse(result.item.value);
res.send(Jsonapi.Serializer.serialize(Jsonapi.AppType, result.item));
} else {
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
} else {
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
} catch (error) {
console.error(error);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
};
exports.deleteEmailDetails = async (req, res) => {
try {
const { url } = helpers.extractAttributes(req.body);
const storageConnection = getStorageConnection();
const data = await storageConnection.deleteConfig('emailIntegration');
if (data) {
res.send(Jsonapi.Serializer.serialize(Jsonapi.AppType, { url }));
} else {
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
} catch (error) {
console.error(error);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
};
const Jsonapi = require('../utils/jsonapiUtil');
const { getStorageConnection } = require('../storageConnection');
const helpers = require('../utils/helpers');

@@ -43,1 +44,59 @@ exports.getLogs = async (req, res) => {

};
exports.getLogsTTL = async (req, res) => {
try {
const storageConnection = getStorageConnection();
const result = await storageConnection.getConfig('logsTTL');
if (result && result.item) {
res.send(Jsonapi.Serializer.serialize(Jsonapi.UserType, result.item));
} else {
const errorData = [{
error: 'Bad Request',
message: 'invalid request'
}];
res.status(400).send({ errors: errorData });
}
} catch (error) {
console.error(error);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
};
exports.updateLogsTTL = async (req, res) => {
try {
const { ttl } = helpers.extractAttributes(req.body);
if (ttl) {
const storageConnection = getStorageConnection();
const result = await storageConnection.setConfig('logsTTL', ttl);
if (result && result.item) {
await storageConnection.ensureLogsTTL();
res.send(Jsonapi.Serializer.serialize(Jsonapi.UserType, result.item));
} else {
const errorData = [{
error: 'Bad Request',
message: 'invalid request'
}];
res.status(400).send({ errors: errorData });
}
} else {
const errorData = [{
error: 'Bad Request',
message: 'invalid request'
}];
res.status(400).send({ errors: errorData });
}
} catch (error) {
console.error(error);
res.status(500).send({
errors: [{
error: 'Internal Server Error',
message: 'An unexpected error occurred'
}]
});
}
};

@@ -22,9 +22,15 @@ const express = require('express');

router.get('/api/apps/check-updates', auth.authenticateToken, appController.checkUpdates);
router.get('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.getSlack);
router.post('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.addSlack);
router.patch('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.updateSlack);
router.delete('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.deleteSlack);
router.get('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.getSlackDetails);
router.post('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.addSlackDetails);
router.patch('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.updateSlackDetails);
router.delete('/api/apps/integrations/slack', auth.authenticateTokenWithAdmin, appController.deleteSlackDetails);
router.get('/api/apps/integrations/email', auth.authenticateTokenWithAdmin, appController.getEmailDetails);
router.post('/api/apps/integrations/email', auth.authenticateTokenWithAdmin, appController.addEmailDetails);
router.patch('/api/apps/integrations/email', auth.authenticateTokenWithAdmin, appController.updateEmailDetails);
router.delete('/api/apps/integrations/email', auth.authenticateTokenWithAdmin, appController.deleteEmailDetails);
router.get('/api/logs', auth.authenticateToken, logController.getLogs);
router.get('/api/logs/config/ttl', auth.authenticateTokenWithAdmin, logController.getLogsTTL);
router.patch('/api/logs/config/ttl', auth.authenticateTokenWithAdmin, logController.updateLogsTTL);
module.exports = router;
const { getStorageConnection } = require('../storageConnection');
const axios = require('axios');
const nodemailer = require('nodemailer');
exports.customLoggerAlert = async function (message, messageExtraInfo) {
await SlackService.sendAlert(message, 'Alert', messageExtraInfo);
await EmailService.sendAlert(message, 'Alert', messageExtraInfo);
};
exports.handleUncaughtExceptions = async function (message, messageExtraInfo) {
await SlackService.sendAlert(message, 'Uncaught Exception', messageExtraInfo);
await EmailService.sendAlert(message, 'Uncaught Exception', messageExtraInfo);
};
// Slack

@@ -8,3 +19,3 @@

SlackService.sendAlert = async function (message, type) {
SlackService.sendAlert = async function (message, type, messageExtraInfo) {
try {

@@ -25,3 +36,3 @@ const storageConnection = getStorageConnection();

const webhookUrl = parsedValue.url;
const payload = blockKit(message, type);
const payload = blockKit(message, type, messageExtraInfo);

@@ -37,40 +48,102 @@ payload.username = parsedValue.username || 'Errsole';

function blockKit (message, type) {
function blockKit (message, type, messageExtraInfo = {}) {
const payload = {
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: ' :warning: *' + type + '*'
}
},
{
type: 'rich_text',
elements: [
{
type: 'rich_text_preformatted',
elements: [
{
type: 'text',
text: message
}
]
}
]
},
{
type: 'divider'
}
]
blocks: []
};
payload.blocks.push({ type: 'section', text: { type: 'mrkdwn', text: ' :warning: *Errsole: ' + type + '*' } });
if (messageExtraInfo.appName) {
payload.blocks.push({ type: 'rich_text', elements: [{ type: 'rich_text_section', elements: [{ type: 'text', text: 'App Name: ', style: { bold: true } }, { type: 'text', text: messageExtraInfo.appName + ' app' }] }] });
}
if (messageExtraInfo.environmentName) {
payload.blocks.push({ type: 'rich_text', elements: [{ type: 'rich_text_section', elements: [{ type: 'text', text: 'Environment Name: ', style: { bold: true } }, { type: 'text', text: messageExtraInfo.environmentName + ' environment' }] }] });
}
if (messageExtraInfo.serverName) {
payload.blocks.push({ type: 'rich_text', elements: [{ type: 'rich_text_section', elements: [{ type: 'text', text: 'Server Name: ', style: { bold: true } }, { type: 'text', text: messageExtraInfo.serverName }] }] });
}
payload.blocks.push({ type: 'rich_text', elements: [{ type: 'rich_text_preformatted', elements: [{ type: 'text', text: message }] }] });
return payload;
}
exports.customLoggerAlert = async function (message) {
await SlackService.sendAlert(message, 'Alert');
// Email
const EmailService = {
transporter: null
};
exports.handleUncaughtExceptions = async function (message) {
await SlackService.sendAlert(message, 'Uncaught Exception');
EmailService.emailTransport = async function () {
try {
if (this.transporter === null) {
const storageConnection = getStorageConnection();
const data = await storageConnection.getConfig('emailIntegration');
if (data && data.item) {
const parsedValue = JSON.parse(data.item.value);
this.transporter = nodemailer.createTransport({
pool: true,
maxConnections: 5,
maxMessages: 100,
rateLimit: 10,
host: parsedValue.host,
port: parseInt(parsedValue.port),
secure: parseInt(parsedValue.port) === 465,
auth: {
user: parsedValue.username,
pass: parsedValue.password
}
});
}
}
} catch (error) {
console.error('Failed to create email transporter: ', error);
}
};
EmailService.sendAlert = async function (message, type, messageExtraInfo) {
try {
await EmailService.emailTransport();
if (this.transporter !== null) {
const storageConnection = getStorageConnection();
const data = await storageConnection.getConfig('emailIntegration');
if (data && data.item) {
const parsedValue = JSON.parse(data.item.value);
if (parsedValue.status === false) {
return false;
}
let subject;
let messagePrefix = '';
if (messageExtraInfo.appName && messageExtraInfo.environmentName) {
subject = 'Errsole: ' + type + ' (' + messageExtraInfo.appName + ' app, ' + messageExtraInfo.environmentName + ' environment)';
messagePrefix = 'App Name: ' + messageExtraInfo.appName + '\nEnvironment Name: ' + messageExtraInfo.environmentName;
} else {
if (messageExtraInfo.appName) {
subject = 'Errsole: ' + type + ' (' + messageExtraInfo.appName + ' app)';
messagePrefix = 'App Name: ' + messageExtraInfo.appName;
} else if (messageExtraInfo.environmentName) {
subject = 'Errsole: ' + type + ' (' + messageExtraInfo.appName + ' environment)';
messagePrefix = 'Environment Name: ' + messageExtraInfo.environmentName;
} else {
subject = 'Errsole: ' + type;
}
}
if (messageExtraInfo.serverName && messagePrefix !== '') {
messagePrefix = messagePrefix + '\nServer Name: ' + messageExtraInfo.serverName;
} else if (messageExtraInfo.serverName) {
messagePrefix = 'Server Name: ' + messageExtraInfo.serverName;
}
if (messagePrefix !== '') {
message = messagePrefix + '\n\n' + message;
}
await this.transporter.sendMail({
from: parsedValue.sender,
to: parsedValue.receivers,
subject,
text: message
});
}
}
} catch (error) {}
};
{
"name": "errsole",
"version": "2.3.0",
"version": "2.4.0",
"description": "Logger with a Built-in Web Dashboard",

@@ -33,4 +33,6 @@ "keywords": [

"express-static-gzip": "^2.1.7",
"http-proxy-middleware": "^3.0.0",
"json-api-serializer": "^2.6.6",
"jsonwebtoken": "^9.0.2",
"nodemailer": "^6.9.13",
"strip-ansi": "^6.0.1",

@@ -37,0 +39,0 @@ "uuid": "^9.0.1"

@@ -17,7 +17,7 @@ <p align="center">

* **Customized Logging:** Errsole's custom logger provides multiple log levels, thereby enabling greater precision in logging. Additionally, you can include metadata with your logs and receive alerts for specific log events according to your preferences.
* **Customized Logging:** Errsole's custom logger provides multiple log levels, thereby enabling greater precision in logging. Additionally, you can include metadata with your logs and receive alerts for specific log events according to your preferences. [Read More](#custom-logging-functions)
* **Centralized Logging:** Errsole consolidates all your app logs from multiple servers into one centralized database. You can choose your preferred database system.
* **Interactive Web Dashboard:** Easily view, filter, and search your app logs using the Errsole web dashboard.
* **Interactive Web Dashboard:** Easily view, filter, and search your app logs using the Errsole Web Dashboard.

@@ -28,15 +28,54 @@ * **Secure Access Control:** Errsole comes with built-in authentication, ensuring that only you and your authorized development team can access the logs.

* **Data Retention:** You can specify the number of days you wish to keep your app logs.
## Setup
* [Errsole with SQLite (Quick Setup)](docs/sqlite-storage.md)
* [Errsole with MongoDB](docs/mongodb-storage.md)
* [Errsole with MySQL](docs/mysql-storage.md)
* [Errsole with PostgreSQL](docs/postgresql-storage.md)
* [Errsole with SQLite](docs/sqlite-storage.md)
* [Errsole with MariaDB](docs/mariadb-storage.md)
* [Errsole with OracleDB](docs/oracledb-storage.md)
## Web Dashboard
## Web Dashboard Access
After the setup, access the Errsole Web Dashboard at [http://localhost:8001/](http://localhost:8001/). If you have configured Errsole with a different port and path during initialization, remember to replace "8001" in the URL with your chosen port number and add your custom path to the end of the URL.
Once you have completed the setup, access the Errsole Web Dashboard at [http://localhost:8001/](http://localhost:8001/). If you have initialized Errsole using a different port or specified a custom path, make sure to adjust the URL accordingly. Replace 8001 with your chosen port and append your custom path at the end of the URL.
### Proxy Middleware Configuration
Should you encounter issues accessing port 8001, possibly due to firewall constraints, or if you prefer to host the Errsole Web Dashboard on your primary domain/port, configure the Errsole Proxy Middleware in your app. Follow these steps:
1. Specify the custom path for the Errsole Web Dashboard during the initialization of Errsole.
2. Integrate the Errsole Proxy Middleware into your app.
**Example:**
```javascript
const errsole = require('errsole');
const ErrsoleMongoDB = require('errsole-mongodb');
// Initialize Errsole with storage and custom path
errsole.initialize({
storage: new ErrsoleMongoDB('mongodb://localhost:27017/', 'logs'),
path: '/errsole'
});
const express = require('express');
const app = express();
// Use Errsole proxy middleware
app.use(errsole.proxyMiddleware());
app.get('/', function (req, res) {
res.send('Hello World');
});
app.listen(3000);
```
Once you have done that, you will be able to access the Errsole Web Dashboard using the same domain as your app. For example:
* If your local app runs on port 3000, you can access the Errsole Web Dashboard at http://localhost:3000/errsole.
* If your remote app is at https://api.example.com, you can access the Errsole Web Dashboard at https://api.example.com/errsole.
## Custom Logging Functions

@@ -98,6 +137,2 @@

## Upcoming Features
* **Data Retention:** You can specify the number of days you wish to keep your app logs.
## Contribution and Support

@@ -104,0 +139,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc