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

@janiscommerce/log

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@janiscommerce/log - npm Package Compare versions

Comparing version 2.0.0 to 3.0.0

lib/firehose-wrapper.js

9

CHANGELOG.md

@@ -8,2 +8,11 @@ # Changelog

## [3.0.0] - 2020-01-14
### Added
- Log struct and formatting
### Changed
- Uploading logs to Firehose instead S3
- Log `type` field now can be only a string, not a number
- Snake_case fields deprecated, only camelCase
## [2.0.0] - 2019-12-05

@@ -10,0 +19,0 @@ ### Added

6

lib/log-error.js

@@ -9,6 +9,4 @@ 'use strict';

INVALID_LOG: 1,
INVALID_CLIENT: 2,
S3_ERROR: 3,
NO_SERVICE_NAME: 4,
NO_STAGE_NAME: 5
FIREHOSE_ERROR: 2,
NO_ENVIRONMENT: 3
};

@@ -15,0 +13,0 @@

'use strict';
const { struct } = require('superstruct');
const EventEmmiter = require('events');
const UUID = require('uuid/v4');
const AWS = require('aws-sdk');
const LogError = require('./log-error');
const Firehose = require('./firehose-wrapper');
const MAX_ATTEMPTS = 3;
const MAX_TIMEOUT = 500;
const DELIVERY_STREAM_PREFIX = 'JanisTraceFirehose';
const BUCKET_PREFIX = 'janis-trace-service';
const S3 = new AWS.S3({ httpOptions: { timeout: MAX_TIMEOUT } });
const firehose = new Firehose({
region: process.env.AWS_DEFAULT_REGION,
httpOptions: { timeout: MAX_TIMEOUT }
});
const emitter = new EventEmmiter();

@@ -27,102 +28,128 @@

static get _stage() {
static get _env() {
return process.env.JANIS_ENV;
}
static get bucket() {
static get _envs() {
if(!this._bucket)
this.setBucket();
return this._bucket;
return {
local: 'Local',
beta: 'Beta',
qa: 'QA',
prod: 'Prod'
};
}
static set bucket(bucket) {
this._bucket = bucket;
}
static get deliveryStreamName() {
static setBucket() {
if(!this._deliveryStreamName)
this._deliveryStreamName = `${DELIVERY_STREAM_PREFIX}${this._getFormattedEnv()}`;
if(typeof this._stage === 'undefined')
throw new LogError('Unknown stage name', LogError.codes.NO_STAGE_NAME);
this.bucket = `${BUCKET_PREFIX}-${this._stage}`;
return this._deliveryStreamName;
}
static async add(client, log, attempts = 1) {
/**
* Put a log into Firehose
* @param {String} client The client code who created the log
* @param {Object} log The log object
* @example
* add('some-client', {
* type: 'some-type',
* entity: 'some-entity',
* entityId: 'some-entityId',
* message: 'some-message',
* log: {
* some: 'log'
* }
* });
*/
static async add(client, log) {
try {
await this._add(client, log);
log = this._validateLog(log, client);
} catch(err) {
return emitter.emit('create-error', log, err);
}
if(err.name === 'LogError')
return emitter.emit('create-error', log, err);
return this._add(log);
}
if(attempts >= MAX_ATTEMPTS) {
return emitter.emit('create-error', log,
new LogError(`Unable to put the log into S3, max attempts reached: ${err.message}`, LogError.codes.S3_ERROR));
}
return this.add(client, log, ++attempts);
}
/**
* Sets a callback for the specified event name
* @param {String} event The event name
* @param {Function} callback The event callback
* @example
* on('create-error', (log, err) => {...});
*/
static on(event, callback) {
emitter.on(event, callback);
}
static async _add(client, log) {
static _validateLog(rawLog, client) {
if(typeof log.service === 'undefined') {
const logStruct = struct.partial({
id: 'string',
service: 'string',
entity: 'string',
entityId: 'string?|number?',
type: 'string',
log: 'object?|array?',
message: 'string?',
client: 'string',
userCreated: 'string?'
}, {
id: UUID(),
service: this._serviceName,
client
});
if(typeof this._serviceName === 'undefined')
throw new LogError('Unknown service name', LogError.codes.NO_SERVICE_NAME);
try {
log.service = this._serviceName;
}
const validLog = logStruct(rawLog);
if(typeof client !== 'string')
throw new LogError('Invalid or empty client', LogError.codes.INVALID_CLIENT);
if(validLog.log)
validLog.log = JSON.stringify(validLog.log);
this._validateLog(log);
return {
...validLog,
dateCreated: new Date().toISOString()
};
const date = log.date_created ? new Date(log.date_created * 1000) : new Date();
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, 0);
const day = date.getDate().toString()
.padStart(2, 0);
} catch(err) {
throw new LogError(err.message, LogError.codes.INVALID_LOG);
}
}
if(!log.date_created)
log.date_created = Math.floor(date / 1000);
static _getFormattedEnv() {
if(!log.id)
log.id = UUID();
if(this._env && this._envs[this._env])
return this._envs[this._env];
return S3.putObject({
Bucket: this.bucket,
Key: `${client}/${year}/${month}/${day}/${log.service}/${log.entity}/${log.id}.json`,
Body: JSON.stringify(log),
ContentType: 'application/json'
}).promise();
throw new LogError('Unknown environment', LogError.codes.NO_ENVIRONMENT);
}
static _validateLog(log) {
static async _add(log, attempts = 0) {
// Log should be an object (not array)
if(typeof log !== 'object' || Array.isArray(log))
throw new LogError('Invalid log: should be an object', LogError.codes.INVALID_LOG);
try {
// Should have service property with type string
if(typeof log.service !== 'string')
throw new LogError('Invalid log: should have a valid service name and must be a string', LogError.codes.INVALID_LOG);
await firehose.putRecord({
DeliveryStreamName: this.deliveryStreamName,
Record: {
Data: Buffer.from(JSON.stringify(log))
}
});
// Should have entity property with type string
if(typeof log.entity !== 'string')
throw new LogError('Invalid log: should have a valid entity property and must be a string', LogError.codes.INVALID_LOG);
} catch(err) {
// Should have type property with type number or string
if(typeof log.type !== 'string' && typeof log.type !== 'number')
throw new LogError('Invalid log: should have a valid type property and must be a string or number', LogError.codes.INVALID_LOG);
}
attempts++;
static on(event, callback) {
emitter.on(event, callback);
if(attempts >= MAX_ATTEMPTS) {
return emitter.emit('create-error', log,
new LogError(`Unable to put the log into firehose, max attempts reached: ${err.message}`, LogError.codes.FIREHOSE_ERROR));
}
return this._add(log, attempts);
}
}

@@ -129,0 +156,0 @@ }

{
"name": "@janiscommerce/log",
"version": "2.0.0",
"description": "A package for creating logs in S3",
"version": "3.0.0",
"description": "A package for creating logs in Firehose",
"main": "lib/log.js",

@@ -38,4 +38,5 @@ "scripts": {

"aws-sdk": "^2.498.0",
"uuid": "^3.3.2"
"uuid": "^3.3.2",
"superstruct": "0.6.2"
}
}

@@ -6,3 +6,3 @@ # log

A package for creating logs in S3
A package for creating logs in Firehose

@@ -22,14 +22,13 @@ ## Installation

Parameters: `clientCode [String]`, `log [Object]`
Puts the recieved log into the janis-trace-service bucket using the `clientCode` as key prefix.
Puts the recieved log into the janis-trace-firehose
### Log structure
The `log [Object]` parameter have the following structure:
- **`id [String]`** (optional): The ID of the log in UUID V4 format. Default will be auto-generated.
- **`service [String]`** (optional): The service name, if this field not exists, will be obtained from the ENV (**`JANIS_SERVICE_NAME`**)
- **`type [String|Number]`** (required): The log type
- **`type [String]`** (required): The log type
- **`entity [String]`** (required): The name of the entity that is creating the log
- **`entity_id [String]`** (optional): The ID of the entity that is creating the log
- **`entityId [String]`** (optional): The ID of the entity that is creating the log
- **`message [String]`** (optional): A general message about the log
- **`log [Object]`** (optional): This property is a JSON that includes all the technical data about your log.
- **`date_created [unix_timestamp]`** (optional): The date created of the log. Default will be auto-generated.
- **`id [String]`** (optional): The ID of the log in UUID V4 format. Default will be auto-generated.
- **`log [Object|Array]`** (optional): This property is a JSON that includes all the technical data about your log.

@@ -39,2 +38,3 @@ ### Log example

{
id: '0acefd5e-cb90-4531-b27a-e4d236f07539',
type: 'new',

@@ -51,7 +51,6 @@ entity: 'api',

'x-forwarded-proto': 'https',
'x-forwarded-port': '443',
'x-forwarded-port': '443'
},
responseHttpCode: 200
},
id: '0acefd5e-cb90-4531-b27a-e4d236f07539'
}
}

@@ -73,6 +72,4 @@ ```

| 1 | Invalid log |
| 2 | Invalid client |
| 3 | S3 Error |
| 4 | Unknown service name |
| 5 | Unknown stage name |
| 2 | Firehose Error |
| 3 | Unknown stage name |

@@ -88,3 +85,3 @@ In case of error while creating your log into S3, this package will emit an event called `create-error`, you can handle it using the `on()` method.

entity: 'api',
entity_id: 'product',
entityId: 'product',
message: '[GET] Request from 0.0.0.0 of custom_data'

@@ -97,10 +94,2 @@ // ...

});
```
## Notes
In order to connect into S3, this package requires the aws volume in the `docker-compose.yml`.
```yml
volumes:
~/.aws:/root/.aws
```
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