I am creating full mean stack app with
NodeJs , Angular 6 , ExpressJs and MongoDB
I have managed to create a server and its working perfectly, instead of using console.log when logging errors in my app I have decided to use Winston Logger here is what I have now
Server side
var appRoot = require('app-root-path');
var winston = require('winston');
// define the custom settings for each transport (file, console)
var options = {
file: {
level: 'info',
filename: `${appRoot}/logs/app.log`,
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
},
console: {
level: 'debug',
handleExceptions: true,
json: false,
colorize: true,
},
};
// instantiate a new Winston Logger with the settings defined above
const logger = winston.createLogger({
transports: [
new winston.transports.File(options.file),
new winston.transports.Console(options.console)
],
exitOnError: false, // do not exit on handled exceptions
});
// create a stream object with a 'write' function that will be used by `morgan`
logger.stream = {
write: function (message, encoding) {
// use the 'info' log level so the output will be picked up by both transports (file and console)
logger.info(message);
},
};
module.exports = logger;
Note: Winston in server side works perfectly
Client-Side
I want to use winston in my client side angular 6 app .
Example: in one of my components i have this.
import * as logger from "winston";
.........
this.activeRouter.params.subscribe((params) => {
// tslint:disable-next-line:prefer-const
let id = params['id'];
this.moviesService.getReview(id)
.subscribe(review => {
console.log(review);
this.review = review;
});
});
As you can see I am using console.log(review) , Instead of console log I would like to use Winston .
How to use Winston logger in client-side ? am newbie to all this stuff any help will be apreciated.
Yeah it is possible, however default transport for browser is very limited. I recommend to use https://www.npmjs.com/package/winston-transport-browserconsole
npm install winston-transport-browserconsole -S
It is easy to use and supports logging json objects:
import * as winston from "winston";
import BrowserConsole from 'winston-transport-browserconsole';
const level = "debug";
winston.configure({
transports: [
new BrowserConsole(
{
format: winston.format.simple(),
level,
},
),
],
});
winston.debug("DEBUG ", {a: 1, b: "two"});
Yes - it can (technically) be used in the browser. Should it be? Almost definitely not (sadly). Winston is a fantastic logger for node. But, emphasis on "for node". If you want to use it on the client, you would need to add a bunch of node polyfills in addition to winston itself, which is very large relative to other client loggers. Between winston and those polyfills you are going to significantly increase the size of your artifact. Also, just fyi webpack 5 removed those node polyfills, so you would need to add them back manually.
According to this ticket: https://github.com/winstonjs/winston/issues/287 it's almost ready for browser use? Or mostly ready? It sounds like they recently started supporting logging in a browser environment.
Related
I'm building a Node.js application and can't figure out how to configure the winston logger the right way.
What I would like to acchieve:
My application should have 6 custom logging levels (fatal, error, warning, status, info & debug). For those levels, there should be methods such as logger.status(message, ...details).
I would like to be able to pass additional JS objects (details) after the message for debugging/evaluation purposes.
Logs should be printed to the console
All console outputs should look the following:
[ISO Date String] [Level in uppercase]: [Log Message]
fatal & error logs should be printed in red
debug & info logs should only be printed if a constant (e.g. this.debug related to my class) is set to true. debug logs should be printed in yellow.
Logs of all levels should be written to a DailyRotateFile, in the same format as above (except for the colors of course).
Logs should be stored in a MongoDB with the following properties: date, level, message, details (containing all objects passed), label (specifies from which part of the log was sent, to be set manually).
What I've done so far:
As recommended, I've extended the default winston class using TypeScript in order to add methods for my specific logging levels:
import winston = require('winston');
interface Logger extends winston.Logger {
fatal: winston.LeveledLogMethod;
error: winston.LeveledLogMethod;
warning: winston.LeveledLogMethod;
status: winston.LeveledLogMethod;
info: winston.LeveledLogMethod;
debug: winston.LeveledLogMethod;
}
From this interface, I've created an instance like so:
this.logger = <Logger>winston.createLogger({
levels: {
fatal: 0,
error: 1,
warning: 2,
status: 3,
info: 4,
debug: 5
},
level: 'debug',
transports: [
new winston.transports.Console({
}),
new winston.transports.DailyRotateFile({
filename: 'cplus-%DATE%.log',
dirname: this.logsDir,
datePattern: 'YYYY-MM-DD-HH-mm'
}),
new winston.transports.MongoDB({
db: this.dbClient
})
]
});
Basic logging to the console & file using the new methods works fine, for example
this.logger.fatal('Connection to database ' + this.dbUrl + ' failed, cannot start', err);
creates the following output:
{"message":"Connection to database mongodb://localhost:27017 failed, cannot startAuthentication failed.","name":"MongooseServerSelectionError","reason": ...
Now, how do I acchieve the rest, such as formatting and correct storing in MongoDB? I've tried a few different things using the preset Winston formats, with no success.
Best regards!
I am building a negamax engine in Typescript that uses Thread.js web-workers. It is a npm library that will be imported by an application built using webpack.
I am using Rollup to build the engine - how can I export the web-worker files so they are copied into the client's build directory as a separate chunk?
There are plugins for that: Alorel/rollup-plugin-web-worker, darionco/rollup-plugin-web-worker-loader
..but I ended up doing it by scratch, using a separate build configuration for the worker(s). This simply gives me more control over the situation.
Attached is the rollup.config.worker.js that I use.
The main rollup.config.mjs imports this file, has its configuration as the first build configuration. The real build config uses #rollup/plugin-replace to inject the worker's hash to the code loading it.
/*
* Rollup config for building web worker(s)
*
* Imported by the main rollup config.
*/
import sizes from '#atomico/rollup-plugin-sizes'
import resolve from '#rollup/plugin-node-resolve'
import replace from '#rollup/plugin-replace'
import { terser } from 'rollup-plugin-terser'
import {dirname} from 'path'
import {fileURLToPath} from 'url'
const myPath = dirname(fileURLToPath(import.meta.url));
const watch = process.env.ROLLUP_WATCH;
const REGION = process.env.REGION;
if (!REGION) throw new Error("'REGION' env.var. not provided");
let loggingAdapterProxyHash;
const catchHashPlugin = {
name: 'my-plugin',
// Below, one can define hooks for various stages of the build.
//
generateBundle(_ /*options*/, bundle) {
Object.keys(bundle).forEach( fileName => {
// filename: "proxy.worker-520aaa52.js"
//
const [_,c1] = fileName.match(/^proxy.worker-([a-f0-9]+)\.js$/) || [];
if (c1) {
loggingAdapterProxyHash = c1;
return;
}
console.warn("Unexpected bundle generated:", fileName);
});
}
};
const pluginsWorker = [
resolve({
mainFields: ["esm2017", "module"],
modulesOnly: true // "inspect resolved files to assert that they are ES2015 modules"
}),
replace({
'env.REGION': JSON.stringify(REGION),
//
preventAssignment: true // to mitigate a console warning (Rollup 2.44.0); remove with 2.45?
}),
//!watch && terser(),
catchHashPlugin,
!watch && sizes(),
];
const configWorker = {
input: './adapters/logging/proxy.worker.js',
output: {
dir: myPath + '/out/worker', // under which 'proxy.worker-{hash}.js' (including imports, tree-shaken-not-stirred)
format: 'es', // "required"
entryFileNames: '[name]-[hash].js', // .."chunks created from entry points"; default is: '[name].js'
sourcemap: true, // have source map even for production
},
plugins: pluginsWorker
}
export default configWorker;
export { loggingAdapterProxyHash }
Using in main config:
replace({
'env.PROXY_WORKER_HASH': () => {
const hash= loggingAdapterProxyHash;
assert(hash, "Worker hash not available, yet!");
return JSON.stringify(hash);
},
//
preventAssignment: true // to mitigate a console warning (Rollup 2.44.0); remove with 2.45?
}),
..and in the Worker-loading code:
const PROXY_WORKER_HASH = env.PROXY_WORKER_HASH; // injected by Rollup build
...
new Worker(`/workers/proxy.worker-${PROXY_WORKER_HASH}.js?...`);
If anyone wants to get a link to the whole repo, leave a message and I'll post it there. It's still in flux.
Edit:
After writing the answer I came across this: Building module web workers for cross browser compatibility with rollup (blog, Jul 2020)
TL;DR If you wish to use EcmaScript Modules for the worker, watch out! Firefox and Safari don't have the support, as of today. source And the Worker constructor needs to be told that the worker source is ESM.
I am sending logs directly to Elasticsearch from a Node.js app using the winston and winston-elasticsearch packages. Elasticsearch 7.5.1, Logstash & Kibana 7.5.1 were deployed on a remote server using Docker Compose.
Problem 1: After running the node.js file that sends 2 log messages to Elasticsearch, the program does not automatically exit to return to the terminal. Using Node.js v12.6.0 on Mac OS X Mojave 10.14.6.
Problem 2: After these 2 log messages were sent to Elasticsearch, they can be viewed using a web browser at http://<example.com>:9200/logs-2020.02.01/_search.
{"took":5,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":2,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"logs-2020.02.01","_type":"_doc","_id":"85GgA3ABiaPPk4as1pEc","_score":1.0,"_source":{"#timestamp":"2020-02-02T02:00:35.789Z","message":"a debug message","severity":"debug","fields":{}}},{"_index":"logs-2020.02.01","_type":"_doc","_id":"9JGgA3ABiaPPk4as1pEc","_score":1.0,"_source":{"#timestamp":"2020-02-02T02:00:35.791Z","message":"an info log","severity":"info","fields":{}}}]}}
However, these logs do not show up on Kibana, such as the Logs section at https://<example.com>/app/infra#/logs/stream?_g=().
Any idea how to get the logs to also show up on Kibana? Also, why is the Node.js app not exiting after sending the log messages?
Thank you!
Node.js App
const winston = require('winston');
const ElasticsearchWinston = require('winston-elasticsearch');
const options = {
console: {
level: 'debug',
handleExceptions: true,
json: false,
colorize: true
},
elasticsearch: {
level: 'debug',
clientOpts: {
node: 'http://user:pass#example.com:9200',
log: 'debug',
maxRetries: 2,
requestTimeout: 10000,
sniffOnStart: false,
}
}
}
var logger = winston.createLogger({
exitOnError: false,
transports: [
new winston.transports.Console(options.console),
new ElasticsearchWinston(options.elasticsearch)
]
});
logger.debug('a debug message');
logger.info('an info log');
I'm not a node.js expert so I will only focus on the kibana issue. The Logs app is not meant to be for "custom" logs/indices like yours.
As stated in the documentation (https://www.elastic.co/guide/en/kibana/current/xpack-logs.html):
The Logs app in Kibana enables you to explore logs for common servers, containers, and services.
The logs app is for monitoring your infrastructure and ELK-Services, e.g. through certain Beats-modules (e.g. the Elasticsearch-, Kibana- and Logstash-Module of Filebeat).
Also from the docs (https://www.elastic.co/guide/en/kibana/current/xpack-logs-configuring.html):
The default source configuration for logs is specified in the Logs app settings in the Kibana configuration file. The default configuration uses the filebeat-* index pattern to query the data.
This explains why you dont see any data in the logs app since your indices use the 'logs-*' index pattern.
Long story short:
To view the documents in your log-* indices, you need to open the Discovery (first icon on the left sidebar in Kibana) and select the index pattern you already have set up. This is the appropriate way of searching your application data in Kibana.
I hope I could help you.
I'm separating my application in modules, but each of these modules have functions that must me logged. So my idea was to create a file winstonConfig.js which would configure the winston, and then I'd require this file in each of the modules that need to log things. Here's winstonConfig.js:
var winston = require('winston');
winston.add(winston.transports.Riak, { level: 'warn' });
winston.add(winston.transports.File, { filename: 'mylogfile.log', level: 'silly' });
exports.log = winston.log;
exports.debug = winston.debug;
exports.error = winston.error;
(btw, is there a way to export everything once?)
but when I require('./winstonConfig.js') in my index.js, I get:
node_modules/winston/lib/winston/logger.js:481
var instance = created ? transport : (new (transport)(options));
^
TypeError: transport is not a constructor
but the exact same code (without exports) will work without any problem when put in index.js (the problem is that then I cannot import this to other modules)
I got the same error with a new project, but when I was trying to use "logger.transports.DailyRotateFile". Then I realized that my code (that was copied from another project) just works for winston 1 (same version used on the other project). So, I just downgraded the lib to version 1 and everything worked normally:
$ npm uninstall winston --save
$ npm install winston#1.x.x --save
But if you want to use winston 2, I found the solution below to use DailyRotateFile - and, probably, there is a similar solution to use other kind of transports.
var winston = require('winston'), expressWinston = require('express-winston');
winston.transports.DailyRotateFile = require('winston-daily-rotate-file');
It looks like you're missing:
require('winston-riak');
I get the same error with your code.
If I comment out the addition of the Riak transport I get no error.
If I require winston-riak:
var winston = require('winston');
require('winston-riak');
winston.add(winston.transports.Riak, { level: 'warn' });
winston.add(winston.transports.File, { filename: 'mylogfile.log', level: 'debug' });
exports.log = winston.log;
exports.debug = winston.debug;
exports.error = winston.error;
I get error: TypeError: riakjs.getClient is not a function. This appears to be because 'winston-riak' tries to execute riakjs.getClient(options) but, per https://github.com/mostlyserious/riak-js/issues/234, getClient is the exported function, rather than a method of the exported object. The winston-riak module hasn't been updated for 5 years. It seems it is not compatible with the current riak-js, which was updated 2 years ago.
This is my winston logger -
var winston = require('winston')
var logger = new (winston.Logger)({
transports: [
new (winston.transports.File)({
// log which takes care of all the MAS scoring - node clusters and servers
filename: './test.log',
level: 'info',
json: true,
eol: 'rn'
})
]
})
And when I run the actual logger:
logger.info('hi', 'it meeeeee')
logger.info('hi', 'it youuuuuu')
It prints out like this in the test.log file -
{"level":"info","message":"hi it meeeeee","timestamp":"2016-08-18T08:42:01.768Z"}rn{"level":"info","message":"hi it youuuuuu","timestamp":"2016-08-18T08:42:01.770Z"}rn
And I want it to be like this:
{"level":"info","message":"hi it meeeeee","timestamp":"2016-08-18T08:42:01.768Z"}
{"level":"info","message":"hi it youuuuuu","timestamp":"2016-08-18T08:42:01.770Z"}
How is this possible? I have read this question Node.js winston logger; How to start from a newline when insert log into log file? - however it does not solve the issue in my case.
I.e. if I open in Notepad ++, command line or Sublime text I still get the same issue.
Try this eol: \r\n
Look official documentation