commit 5d3bf04dbb7082d91622f819b08fc63ac8743811 Author: kebler.net Date: Sat Jun 12 14:23:41 2021 -0700 initial commit 0.1.0 diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..d3af4fa --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,15 @@ +env: + node: true + es2021: true + mocha: true +extends: + - standard +parserOptions: + ecmaVersion: 12 + sourceType: module +rules: + indent: ["error", 2] + no-console: 0 + semi: ["error", "never"] + # linebreak-style: ["error", "unix"] + quotes: ["error", "single"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0672f1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/node_modules/ +/coverage/ +*.yaml diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..fe99f98 --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +test/ +*.test.js +example/ diff --git a/example/read.js b/example/read.js new file mode 100644 index 0000000..e5bc755 --- /dev/null +++ b/example/read.js @@ -0,0 +1,10 @@ +import db from 'nedb-promises' + +const dbfile = 'example/history.db' + +const history = db.create(dbfile) + +; +(async function () { + console.log(await history.find({ time: { $gt: 1 } })) +})() diff --git a/example/write.js b/example/write.js new file mode 100644 index 0000000..380fdbe --- /dev/null +++ b/example/write.js @@ -0,0 +1,17 @@ +import { write } from '../src/history.js' + +const opts = { + path: 'example/history.db', + name: 'example', + clear: true, + keys: { + test: 'custom common key' + } +} + +const event = write(opts) + +event('something just happened') +event({ state: 'on', zone: 5, msg: 'another thing just happened' }) +event('history writing again') +setTimeout(() => (event('interval')), 10000) diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..0578b79 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,5 @@ +{ + "ignore": [ + "example/*.json" + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..c876bfc --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "@uci-utils/history", + "version": "0.1.0", + "description": "Maintain a history file of events in nljson", + "main": "./src/history.js", + "type": "module", + "scripts": { + "testd": "./node_modules/.bin/nodemon --exec './node_modules/.bin/mocha --timeout 30000' || exit 1", + "test": "./node_modules/.bin/mocha --timeout 30000 || exit 0", + "dev:write": "UCI_ENV=dev ./node_modules/.bin/nodemon example/write", + "dev:read": "UCI_ENV=dev ./node_modules/.bin/nodemon example/read", + "read": "node example/read", + "pro": "UCI_ENV='pro' node example/example", + "pro:path": "UCI_LOG_PATH=./example/example.log npm run pro" + }, + "author": "David Kebler", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/uCOMmandIt/uci-changeme.git" + }, + "keywords": [ + "nodejs", + "history", + "json", + "log" + ], + "bugs": { + "url": "https://github.com/uCOMmandIt/uci-changeme/issues" + }, + "homepage": "https://github.com/uCOMmandIt/uci-changeme#readme", + "dependencies": { + "debounce-fn": "^5.0.0", + "env-paths": "^2.2.1", + "make-dir": "^3.1.0" + }, + "devDependencies": { + "chai": "^4.3.4", + "eslint": "^7.28.0", + "eslint-config-standard": "^16.0.3", + "mocha": "^9.0.0", + "nedb-promises": "^4.1.5", + "nodemon": "^2.0.7" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..bb26e47 --- /dev/null +++ b/readme.md @@ -0,0 +1,4 @@ +# UCommandIt JSONL History +#### maintain history file of events in newline json for a process + +## How to by Example diff --git a/src/history.js b/src/history.js new file mode 100644 index 0000000..79ec96e --- /dev/null +++ b/src/history.js @@ -0,0 +1,52 @@ +import envPaths from 'env-paths' +import { sync as mkdir } from 'make-dir' +import { dirname } from 'path' +import { createWriteStream, createReadStream } from 'fs' +import crypto from 'crypto' +import debounce from 'debounce-fn' + +function write (opts = {}) { + const path = opts.path ? opts.path : `${envPaths(opts.name || 'history', { suffix: null }).log}/${opts.name || process.pid}.log` + mkdir(dirname(path)) // makes recursively for any missing parent directories + + const create = (path, clear) => { + const stream = createWriteStream(path, { flags: `${clear ? 'w' : 'a'}` }) + // todo make sure stream was made + stream.on('close', (data) => { + console.log('the stream to history file was closed') + }) + return stream + } + + let output = create(path, opts.clear) + + const _write = (obj) => { + if (output.writable) { + const tStamp = new Date() + const keys = { + _id: crypto.randomBytes(8).toString('hex'), + time: tStamp.getTime(), + datetime: tStamp.toString(), + utc: tStamp.toISOString() + } + if (typeof obj === 'string') obj = { msg: obj } + obj = Object.assign(keys, opts.keys, obj) + console.log('writing', obj) + output.write(JSON.stringify(obj) + '\n', function () { + debounce(output.destroy.bind(output), { wait: opts.close || 5000 })() + }) + } else { + console.log('there is no stream, recreating') + output = create(path) + _write(obj) + } + } + return _write +} + +function view (handler, opts) { + +} + +export default write +export { write, view } diff --git a/test/history.test.js b/test/history.test.js new file mode 100644 index 0000000..861efe8 --- /dev/null +++ b/test/history.test.js @@ -0,0 +1,92 @@ +import logger from '../src/logger.js' +import { expect } from 'chai' +import { it } from 'mocha' +import { stdout } from 'test-console' +//https://github.com/jamesshore/test-console + +describe('JSON Logging Utility Testing ',async ()=> { + + let log + // let captured = stdout.inspect().output + // let capture = stdout.inspect + // let restore = stdout.inspect().restore + // + class LogTest { + constructor(opts) { + log = logger({ + name: 'test', + id: opts.id, + file: 'example/example.js', + // class: 'LogTest', + // repo:'test repo' + package:'@uci-utils/test' + }) + // console.log('env',process.env.UCI_ENV) + } + async logit(level,msg,props={}) { + Object.assign(props,{msg:msg}) + log[level](props) + } + } + + // TODO this is available from the logger as .levels + let levelName = { + 10:'trace', + 20:'debug', + 30:'info', + 40:'warn', + 50:'error', + 60:'fatal' + } + + let logtest = {} + let inspect = {} + + beforeEach( () => { + // console.log('starting console capture') + inspect = stdout.inspect() + }) + afterEach( () => { + inspect.restore() + // console.log('console.restored') + }) + + + it('check dev output to console' , async function () { + // setup + let msg='test' + let level = 'info' + let moreprops = {} + process.env.UCI_ENV='dev' + logtest = new LogTest({id:'someid'}) + + // create log to stdout + logtest.logit(level,msg,moreprops) + + // test stdout response + let response = inspect.output[0] + expect(response).to.have.string(level.toUpperCase()) && + expect(response).to.have.string(msg) + }) + + it('check json output' , async function () { + // setup + let msg='test' + let level = 'info' + let moreprops = {} + process.env.UCI_ENV='dev' + process.env.UCI_LOG_JSON=true + logtest = new LogTest({id:'someid'}) + + // create log to stdout + logtest.logit(level,msg,moreprops) + + // test stdout response + let response = inspect.output[0] + response = JSON.parse(response) + expect(response.msg).to.equal(msg) && + expect(levelName[response.level]).to.equal(level) + }) + + +})