Express logs resource usage after everything happened for that operation - node.js

I'm using Express 4.17.1 — and Winston 3.3.3 / Morgan 1.10.0 for logging purposes, which I've managed to configure in this way:
import winston from "winston";
const options = {
console: {
colorize: true,
format: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp(),
winston.format.printf((msg) => {
return `${msg.timestamp} [${msg.level}] - ${msg.message}`;
})
),
handleExceptions: true,
json: true,
level: "debug",
},
};
const logger = winston.createLogger({
exitOnError: false,
transports: [new winston.transports.Console(options.console)], // alert > error > warning > notice > info > debug
});
logger.stream = {
write: (message) => {
logger.info(message.slice(0, -1)); // ...use lowest log level so the output will be picked up by any transports
},
};
export { logger };
I then import the Winston config inside application.js where all the Express setup is done like this:
import express from "express";
import morgan from "morgan";
import { logger } from "./config/winston.js";
const app = express();
app.use(express.json());
// ...some more settings
app.use(morgan("dev", { stream: logger.stream })); // combined, dev
// ...route Definitions
export { app };
The issue I have is with some log statements that looks like are automatically handled by Winston (I guess) based on the Express route that was processed (which I like), but they are being logged after all the usual statements for the corresponding workflow. This is an example:
2021-03-03T16:25:22.199Z [info] - Searching all customers...
{
method: 'select',
options: {},
timeout: false,
cancelOnTimeout: false,
bindings: [],
__knexQueryUid: 'dFKYVOlaQyJswbxoex7Y6',
sql: 'select `customers`.* from `customers`'
}
2021-03-03T16:25:22.203Z [info] - Done with all customers workflow...
2021-03-03T16:25:22.215Z [info] - GET /api/customers 200 11.727 ms - 395
I would expect 2021-03-03T16:25:22.215Z [info] - GET /api/customers 200 11.727 ms - 395 to be the very first piece in that workflow because it's the start of it, but it's being logged at the end — which is kind of confusing.
Is there a way to fix this or is this like that by design? If it can be fixed, what should I add/remove/tweak in the Winston config or anywhere else.

According to the morgan-documentation, there's a setting which allows you to write the access-log on request instead of on response (with the latter being the default):
Write log line on request instead of response. This means that a
requests will be logged even if the server crashes, but data from the
response (like the response code, content length, etc.) cannot be
logged.
So passing { immediate: true } to morgan should make the log appear at the beginning of the workflow, but the log will obviously only contain request related data.

Related

How to use fluentbit with Nestjs?

I have a fluentbit running in the Docker container 192.168.1.201:24224 which is connected to the elasticsearch.
Now, I am trying to connect my nestjs logger to the fluentbit:
logger.ts
import * as winston from 'winston';
var config = {
host: '192.168.1.201',
port: 24224,
timeout: 3.0,
requireAckResponse: true, // Add this option to wait response from Fluentd certainly
};
var fluentTransport = require('fluent-logger').support.winstonTransport();
var fluent = new fluentTransport('test', config);
// Initialize Winston Logger
const logger = winston.createLogger({
level: 'verbose',
format: winston.format.json(),
defaultMeta: { service: 'test-service' },
transports: [
fluent,
new winston.transports.Console({
format: winston.format.json(),
}),
],
});
export default logger;
I am using the logger in this way:
loggservice.ts:
async log_info(
tracking_id: any,
) {
logger.log({
tracking_id: tracking_id,
});
}
then, in the function :
test.ts:
log_info(tracking_id)
It seems that it can not send the log to the fluentbit(so that I can get the log in ES), am I missing something here?

Transport winston logs to a server

i was reading through the winston documentation and I came across the following statement
A transport is essentially a storage device for your logs
So I assumed if i set up a http transport i would be able to aggregate the logs somewhere else. In my case in an application running in localhost:3210
Does anybody know why I'm not receiving the log I'm trying to send ?
Here is my code:
import { createLogger, format, transports } from 'winston';
const { combine, timestamp, label, printf} = format;
const myFormat = printf(({ level, message, label, timestamp }) => {
return `${timestamp} [${label}] ${level}: ${message}`;
});
export const logger = createLogger({
format: combine(label({ label: 'Test Service' }), timestamp(), myFormat),
transports: [
new transports.Http({
host: 'localhost',
port: 3210,
path: '/'
})
]
});
logger.log({
level: 'info',
message: `Hello there`
});
Try logger.info('Hello there');. Also, no idea how your server looks like, but make sure it has a defined POST method with the required path.

ExpressWinston does not log on 200 HTTP response code

I am using ExpressWinston for logging in Node.js app. Can we log requests for each static resources which are being called ?
Logger does not log if file is found (200), but it logs when file not found (404).
For example, if request is valid like http://domain/css/existingfile.css, Logger doesnot log.
However, if request is invalid like http://domain/css/non-existingfile.css, Logger logs with proper 404 status code.
I need log when file is also found (200). How can be expressWinston configured that it logs for all the requests with whatever status code returned by server ?
Regards
The configuration I have below logs all request in a mongodb database using ExpressWinston and winston-mongodb, regardless of the status code. You can change the transport to console or file depending on what you want. You will get the relevant meta data for each request and response based on your whiteList.
expressWinston.responseWhitelist.push('body')
const requestLog = expressWinston.logger({
transports: [
new winston.transports.MongoDB({
db: db,
options: {
useNewUrlParser: true,
poolSize: 2,
autoReconnect: true
}
})
],
meta: true,
msg: (req, res) => 'HTTP {{req.method}} {{req.url}};',
requestWhitelist: [
'url',
'method',
'httpVersion',
'originalUrl',
'query',
'body'
]
});
Just replace the code in the transports array with
transports: [
new winston.transports.Console()
]
if you want to display in the console.

How to catch errors on Winston Http Transport

I'm creating a logging framework using winston. Basically using built in winston http transport. My question is, how should I catch any http exceptions that might have occurred while making http post request due to invalid host/path/auth. Below is my code structure-
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, label, printf } = format;
const transportOptions = {
host: 'host',
port: 'port',
path: '/',
auth: '',
};
const myFormat = printf(debug => {
var msg = {
timestamp: debug.timestamp,
label: debug.label,
level: debug.level,
message: debug.message,
};
return JSON.stringify(msg);
});
const logger = createLogger({
level: 'debug',
format: combine(label({ label: 'label' }), timestamp(), myFormat),
transports: [
new transports.Console(),
new transports.Http(transportOptions),
],
json: false,
});
logger.info('Test');
If I provide wrong value in transportOptions it just does nothing. I want my framework through some sort of exception so that I would know when any error/exception occurs. Can anyone please give me any suggestion?
According to https://github.com/winstonjs/winston/blob/master/lib/winston/transports/http.js#L57 , it looks like the HTTP transport emits a 'warn' event if the HTTP response code isn't 200. So as long as your server returns non-200 when there's an error, then you could listen to the 'warn' event from your transport and process the error accordingly (throw an exception or whatever you want). Here is example code (I tested and it works):
// Declare your transport outside the logger definition
const t = new transports.Http(transportOptions);
...
t.on('warn', (e) => console.log('warning! ' + e));
logger.info('Test'); // 'warning! ...'
Note that if the server gives no response, then the transport doesn't report a warning; whether that is a bug or feature I'm not sure... :)

Winston not Logging to console in typescript

I am confused by winston. I am using the following typescript code to log onto the console in my *.ts file:
import { Logger, LoggerInstance } from "winston";
const logger:LoggerInstance = new Logger();
logger.info('Now my debug messages are written to the console!');
the console remains empty. There are no compile errors or other issues.
At the same time the following works fine:
const wnstn = require("winston");
wnstn.info('Finally my messages are written to the console!');
Does anyone have a clue why that is the case? Do I have to configure the Logger differently? How would I use the defaults I get from the second example?
This is the Typescript way to import Winston.
First, be sure you have installed the typing :
npm i -D #types/winston
Then, in your script.ts
import { Logger, transports } from 'winston';
var logger = new Logger({
transports: [
new transports.Console(),
new transports.File ({ filename: 'somefile.log' })
]
});
In genral, you can import all constants and types without using winston.<...> before.
When you instantiate a new Logger instance you need to provide it a list of transports so it knows where to send the logs:
var logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)(),
new (winston.transports.File)({ filename: 'somefile.log' })
]
});
Well,
thanks to the hint of #idbehold , I found that a plain and easy:
import * as winston from "winston";
winston.info('Now my debug messages are written to the console!');
works for the default logger..
Well, I am following below file as winston.ts
import * as appRoot from 'app-root-path';
import * as winston from 'winston';
// define the custom settings for each transport (file, console)
const 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.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`
const myStream = {
write: (message: string) => {
// use the 'info' log level so the output will be picked up by both transports (file and console)
logger.info(message);
}
};
export default logger;
as using inside app.ts as this.app.use(morgan('combined', { stream: winston.stream }));

Resources