Skip to content

Commit

Permalink
Merge 9d16adf into b09c210
Browse files Browse the repository at this point in the history
  • Loading branch information
Nataniel López committed Aug 6, 2019
2 parents b09c210 + 9d16adf commit 1a40c30
Show file tree
Hide file tree
Showing 14 changed files with 3,826 additions and 1 deletion.
122 changes: 122 additions & 0 deletions .eslintrc.js
@@ -0,0 +1,122 @@
'use strict';

module.exports = {
extends: 'airbnb-base',

env: {
node: true,
es6: true,
mocha: true
},

globals: {
__rootpath: true,
coreRequire: true,
mainRequire: true,
JANIS_CORE: true,
JANIS_ENV: true,
JANIS_ENV_ALIAS: true
},

parserOptions: {
sourceType: 'script'
},

settings: {
'import/core-modules': ['aws-sdk', 'lodash', 'yamljs', 'openapi-schema-validator']
},

rules: {
'operator-linebreak': 0,
'no-continue': 0,
'no-plusplus': 0,
'prefer-spread': 0,
'prefer-rest-params': 0,
'class-methods-use-this': 0,
'consistent-return': 0,
'prefer-template': 0,
'import/no-unresolved': 0,
'import/no-extraneous-dependencies': ['error', { devDependencies: ['**/tests/**/*.js'] }],

'no-bitwise': 0,

curly: ['error', 'multi-or-nest'],

'no-underscore-dangle': ['warn', {
allowAfterThis: true,
allowAfterSuper: true,
allow: ['_call', '__rootpath', '_where']
}],

'no-tabs': 0,

'no-new': 0,

'func-names': 0,

'space-before-function-paren': ['error', {
'anonymous': 'never',
'named': 'never',
'asyncArrow': 'always'
}],

'arrow-parens': ['error', 'as-needed'],
'arrow-body-style': 0,

indent: ['error', 'tab', {
SwitchCase: 1
}],

'comma-dangle': ['error', 'never'],

'padded-blocks': 0,

'max-len': ['error', {
code: 150,
tabWidth: 1,
comments: 200
}],

'spaced-comment': ['error', 'always', {
exceptions: ['*']
}],

'newline-per-chained-call': ['error', {
ignoreChainWithDepth: 2
}],

'no-param-reassign': 0,

'no-prototype-builtins': 0,

'keyword-spacing': ['error', {
overrides: {
if: {
after: false
},
for: {
after: false
},
while: {
after: false
},
switch: {
after: false
},
catch: {
after: false
}
}
}],

'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'],
'function-paren-newline': 0,
'no-await-in-loop': 0,

'object-curly-newline': ['error', {
ObjectExpression: { minProperties: 5, multiline: true, consistent: true },
ObjectPattern: { minProperties: 5, multiline: true, consistent: true }
}],
'nonblock-statement-body-position': ['error', 'below', { overrides: { else: 'any' } }]
}
};
61 changes: 61 additions & 0 deletions .gitignore
@@ -0,0 +1,61 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next
5 changes: 5 additions & 0 deletions .huskyrc.json
@@ -0,0 +1,5 @@
{
"hooks": {
"pre-commit": "npm run lint && npm t"
}
}
20 changes: 20 additions & 0 deletions .nycrc
@@ -0,0 +1,20 @@
{
"exclude": [
"coverages/",
"tests/",
"mocks/",
".eslintrc.js",
".travis.yml"
],
"extension": [
".js"
],
"cache": true,
"all": true,
"default-excludes": true,
"check-coverage": true,
"statements": 95,
"branches": 95,
"functions": 95,
"lines": 95
}
15 changes: 15 additions & 0 deletions .travis.yml
@@ -0,0 +1,15 @@
language: node_js
node_js:
- "lts/*"
cache: npm
script:
- |
# Run test script
npm run test-ci
after_script:
- |
# Upload coverage to coveralls
if [[ -d .nyc_output ]]; then
npm install --save-dev coveralls@2
nyc report --reporter=text-lcov | coveralls
fi
12 changes: 12 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,12 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Log package
- Unit tests
- Docs
29 changes: 28 additions & 1 deletion README.md
Expand Up @@ -11,12 +11,39 @@ npm install @janiscommerce/log
```

## API
- `add(log, bucketName)`
Parameters: `log [Object]`, `bucketName [String]`
Puts the recieved log into the specified S3 bucket.

## Errors

The errors are informed with a `LogError`.
This object has a code that can be useful for a correct error handling.
The codes are the following:

| Code | Description |
|------|--------------------------------|
| 1 | Invalid log |
| 2 | Invalid bucket |
| 3 | S3 Error |

## Usage
```js
const Log = require('@janiscommerce/log');

Log.add({
type: 1,
entity: 'api',
entity_id: 'product',
message: '[GET] Request from 0.0.0.0 of custom_data'
// ...
}, 'my-bucket');
```

## Examples
## Notes
In order to connect into S3, this package requires the aws volume in the `docker-compose.yml`.

```yml
volumes:
~/.aws:/root/.aws
```
5 changes: 5 additions & 0 deletions index.js
@@ -0,0 +1,5 @@
'use strict';

const { Log } = require('./lib');

module.exports = Log;
9 changes: 9 additions & 0 deletions lib/index.js
@@ -0,0 +1,9 @@
'use strict';

const Log = require('./log');
const LogError = require('./log-error');

module.exports = {
Log,
LogError
};
23 changes: 23 additions & 0 deletions lib/log-error.js
@@ -0,0 +1,23 @@
'use strict';

class LogError extends Error {

static get codes() {

return {
INVALID_LOG: 1,
INVALID_BUCKET: 2,
S3_ERROR: 3
};

}

constructor(err, code) {
super(err);
this.message = err.message || err;
this.code = code;
this.name = 'LogError';
}
}

module.exports = LogError;
74 changes: 74 additions & 0 deletions lib/log.js
@@ -0,0 +1,74 @@
'use strict';

const EventEmmiter = require('events');

const UUID = require('uuid/v4');

const AWS = require('aws-sdk');

const LogError = require('./log-error');

const MAX_ATTEMPTS = 3;

const MAX_TIMEOUT = 500;

const S3 = new AWS.S3({ httpOptions: { timeout: MAX_TIMEOUT } });

const emitter = new EventEmmiter();

class Log {

static async add(bucket, log, attempts = 1) {

try {

await this._add(bucket, log);

} catch(err) {

if(err.name === 'LogError')
return emitter.emit('create-error', log, err);

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(bucket, log, ++attempts);
}
}

static async _add(bucket, log) {

if(!bucket || typeof bucket !== 'string')
throw new LogError('Invalid or empty bucket', LogError.codes.INVALID_BUCKET);

if(!log || typeof log !== 'object' || Array.isArray(log))
throw new LogError('Invalid log', LogError.codes.INVALID_LOG);

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);

if(!log.date_created)
log.date_created = Math.floor(date / 1000);

if(!log.id)
log.id = UUID();

return S3.putObject({
Bucket: bucket,
Key: `logs/${year}/${month}/${day}/${log.id}.json`,
Body: JSON.stringify(log),
ContentType: 'application/json'
}).promise();
}

static on(event, callback) {
emitter.on(event, callback);
}
}

module.exports = Log;

0 comments on commit 1a40c30

Please sign in to comment.