diff --git a/examples/NodeInterprocess/README.md b/examples/NodeInterprocess/README.md new file mode 100644 index 00000000..0207a57b --- /dev/null +++ b/examples/NodeInterprocess/README.md @@ -0,0 +1,22 @@ +# Realm-JS Interprocess Example +Example of interprocess support using Realm and Node.js + +The example makes use of [Winston](https://github.com/winstonjs/winston), a +logging library, and includes `winston-realm.js` which defines a custom transport +utilizing Realm for storage. The main file, `index.js` is an +[Express](https://github.com/expressjs/express) app handling HTTP requests. The +app listens on port 3000 and responds with "Hello World!" at the base path `/` +and logs at `info` "Handled Hello World" to Winston. At any other path it +returns a `404` error and logs an error message to Winston with URL in question. + +Since the log messages are being stored in a Realm (`winston.realm`), we can +listen for changes on another process. The `listener.js` is a small example of +this. When running, this listens to the `winston.realm` for changes and writes +to the console the latest error level log message. + +To test: + +1. `npm install` +2. `node .` to run the Express app +3. In another process: `node listener.js` +4. Go to `http://localhost:3000/whatever` to see error message across processes diff --git a/examples/NodeInterprocess/index.js b/examples/NodeInterprocess/index.js new file mode 100644 index 00000000..9570a3eb --- /dev/null +++ b/examples/NodeInterprocess/index.js @@ -0,0 +1,25 @@ +var express = require('express'), + util = require('util'), + winston = require('winston'); + RealmWinston = require('./winston-realm').Realm; + +var app = express(); + +// Use custom Winston transport: RealmWinston +// Writes log data to winston.realm +winston.add(RealmWinston, {}); + +app.get('/', function (req, res) { + res.send('Hello World!'); + winston.info('Handled Hello World'); +}); + +app.use(function (req, res, next) { + res.status(404).send('Sorry can not find that!'); + winston.error('404 Error at: ' + req.url); +}) + +app.listen(3000, function () { + console.log('Example app listening on port 3000!'); +}); + diff --git a/examples/NodeInterprocess/listener.js b/examples/NodeInterprocess/listener.js new file mode 100644 index 00000000..e901df94 --- /dev/null +++ b/examples/NodeInterprocess/listener.js @@ -0,0 +1,16 @@ +'use strict'; + +var Realm = require('realm'); + +let winstonRealm = new Realm({ + path: 'winston.realm' +}); + +// Register listener to print out log messages at error level +winstonRealm.objects('Log').filtered('level = "error"').addListener((logs, changes) => { + changes.insertions.map((index) => { + let log = logs[index]; + console.log(log.message); + }) +}); + diff --git a/examples/NodeInterprocess/package.json b/examples/NodeInterprocess/package.json new file mode 100644 index 00000000..f99ed8a8 --- /dev/null +++ b/examples/NodeInterprocess/package.json @@ -0,0 +1,17 @@ +{ + "name": "winston-realm-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": { + "express": "^4.14.0", + "realm": "^0.15.0", + "winston": "^2.3.0" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/examples/NodeInterprocess/winston-realm.js b/examples/NodeInterprocess/winston-realm.js new file mode 100644 index 00000000..5366f249 --- /dev/null +++ b/examples/NodeInterprocess/winston-realm.js @@ -0,0 +1,62 @@ +'use strict'; + +var util = require('util'), + winston = require('winston'), + Realm = require('realm'); + +var RealmLogger = exports.Realm = function (options) { + winston.Transport.call(this, options); + + // + // Configure the Realm` + // + let LogSchema = { + name: 'Log', + properties: { + level: 'string', + message: 'string', + timestamp: 'date', + } + }; + + this.realm = new Realm({ + path: 'winston.realm', + schema: [LogSchema] + }); +}; + +// +// Inherit from `winston.Transport` so you can take advantage +// of the base functionality and `.handleExceptions()`. +// +util.inherits(RealmLogger, winston.Transport); + +// +// Expose the name of this Transport on the prototype +// +RealmLogger.prototype.name = 'realm'; + +// +// Define a getter so that `winston.transports.Realm` +// is available and thus backwards compatible. +// +winston.transports.Realm = RealmLogger; + +// +// ### function log (level, msg, [meta], callback) +// #### @level {string} Level at which to log the message. +// #### @msg {string} Message to log +// #### @meta {Object} **Optional** Additional metadata to attach +// #### @callback {function} Continuation to respond to when complete. +// Core logging method exposed to Winston. Metadata is optional. +// +RealmLogger.prototype.log = function (level, msg, meta, callback) { + let ts = new Date(); + + this.realm.write(() => { + this.realm.create('Log', {level: level, message: msg, timestamp: ts}); + }); + + callback(null, true); +}; +