The Functions Transport.prototype.normalizeQuery, Transport.prototype.formatResults and common.clone were removed in 3.0.0, so query will throw an unhandled exception.
For others that have the same problem here is a temporary hack that lets query() work as intended.
// TODO REMOVE WHEN FIXED
// necessary workarounds for winston 3.0.0-rc1..
function clone(obj) {
var copy = Array.isArray(obj) ? [] : {};
for (var i in obj) {
if (Array.isArray(obj[i])) {
copy[i] = obj[i].slice(0);
} else if (obj[i] instanceof Buffer) {
copy[i] = obj[i].slice(0);
} else if (typeof obj[i] != 'function') {
copy[i] = obj[i] instanceof Object ? clone(obj[i]) : obj[i];
} else if (typeof obj[i] === 'function') {
copy[i] = obj[i];
}
}
return copy;
}
require("winston/lib/winston/common").clone = clone;
let Transport = require("winston-transport");
Transport.prototype.normalizeQuery = function (options) { //
options = options || {};
// limit
options.rows = options.rows || options.limit || 10;
// starting row offset
options.start = options.start || 0;
// now
options.until = options.until || new Date;
if (typeof options.until !== 'object') {
options.until = new Date(options.until);
}
// now - 24
options.from = options.from || (options.until - (24 * 60 * 60 * 1000));
if (typeof options.from !== 'object') {
options.from = new Date(options.from);
}
// 'asc' or 'desc'
options.order = options.order || 'desc';
// which fields to select
options.fields = options.fields;
return options;
};
Transport.prototype.formatResults = function (results, options) {
return results;
};
Thanks @Kouzukii, I had to do the same, taking as an example the v 2.x.
@Kouzukii , this blows up for me:
{ file: SyntaxError: Unexpected token l in JSON at position 2
at JSON.parse (<anonymous>)
at add (node_modules/winston/lib/winston/transports/file.js:223:22)
at ReadStream.<anonymous> (node_modules/winston/lib/winston/transports/file.js:203:9)
at ReadStream.emit (events.js:159:13)
at addChunk (_stream_readable.js:265:12)
at readableAddChunk (_stream_readable.js:248:13)
at ReadStream.Readable.push (_stream_readable.js:209:10)
at onread (fs.js:2115:12)
at FSReqWrap.wrapper [as oncomplete] (fs.js:676:17) }
@indexzero I'd like to work on this but I'm unsure of the direction. There must have been a reason for removing some of these functions. Should I reuse 2.x code or did you have something else in mind.
How to use this hack?
Hey since there's some unclarity here,
You have to put the code I posted above into a JavaScript-file (let's call it winston-workaround.js)
And at the very top of your app.js (the JavaScript file you're starting with npm start) you put
require('./winston-workaround');
// or with babel
import './winston-workaround'
And the example posted by the Winston team should work (tested with winston 3.0.0).
If I get some time soon, I'll open a pull request that resolves this issue.
Thank you @Kouzukii, I did what you recommended
winston-workaround.js
// TODO REMOVE WHEN FIXED
// necessary hacks for winston 3.0.0-rc1..
function clone (obj) {
var copy = Array.isArray(obj) ? [] : {}
for (var i in obj) {
if (Array.isArray(obj[i])) {
copy[i] = obj[i].slice(0)
} else if (obj[i] instanceof Buffer) {
copy[i] = obj[i].slice(0)
} else if (typeof obj[i] !== 'function') {
copy[i] = obj[i] instanceof Object ? clone(obj[i]) : obj[i]
} else if (typeof obj[i] === 'function') {
copy[i] = obj[i]
}
}
return copy
}
require('winston/lib/winston/common').clone = clone
let Transport = require('winston-transport')
Transport.prototype.normalizeQuery = function (options) {
options = options || {}
// limit
options.rows = options.rows || options.limit || 10
// starting row offset
options.start = options.start || 0
// now
options.until = options.until || new Date()
if (typeof options.until !== 'object') {
options.until = new Date(options.until)
}
// now - 24
options.from = options.from || (options.until - (24 * 60 * 60 * 1000))
if (typeof options.from !== 'object') {
options.from = new Date(options.from)
}
// 'asc' or 'desc'
options.order = options.order || 'desc'
// which fields to select
options.fields = options.fields
return options
}
Transport.prototype.formatResults = function (results, options) {
return results
}
and this is my entry point
require('./tools/winston-workaround')
/* Core Libraries */
import chokidar from 'chokidar'
import chalk from 'chalk'
import fs from 'fs'
import path from 'path'
import moment from 'moment'
/* App Libraries */
import { db } from './database'
import upload from './upload'
/* App Config */
import { logger } from './tools'
import CONFIG from '../config.json'
const { AWS: { S3: S3Config } } = CONFIG
const Op = db.Sequelize.Op
...
..
.
const options = {
from: global.processTimeStart,
until: timeEnd
}
logger.query(options, (err, results) => {
if (err) {
throw err
}
console.log(results)
})
but I still have the same error TypeError: clone is not a function, will it be maybe my winston configuration?.
This is my winston configuration
logger/index.js
import { createLogger, format, transports } from 'winston'
import path from 'path'
import moment from 'moment'
// import CustomTransport from './customTransport'
import stripAnsi from 'strip-ansi'
import CONFIG from '../../config.json'
const { combine, printf } = format
const frmtLog = printf(info => {
// Remove Colors Characters
const level = stripAnsi(info.level)
const message = stripAnsi(info.message)
const now = moment(info.timestamps).format('YYYY-MM-DD hh:mm:ss')
return `[${now}] ${level}: ${message}`
})
const logger = createLogger({
format: combine(
frmtLog
),
transports: [
new transports.File({
filename: path.join(CONFIG.LOGS, 'info.log'),
level: 'info'
}),
new transports.File({
filename: path.join(CONFIG.LOGS, 'warning.log'),
level: 'warning'
}),
new transports.File({
filename: path.join(CONFIG.LOGS, 'error.log'),
level: 'error'
}),
new transports.File({
filename: path.join(CONFIG.LOGS, 'combined.log')
})
]
})
if (process.env.NODE_ENV !== 'production') {
logger.add(new transports.Console({
format: format.combine(
format.colorize({
all: true
}),
format.simple()
)
}))
}
@jnreynoso that's interesting, I just tried this with Babel and it seems that babel sorts the import instructions to be above the require() instruction, so clone isn't set by the workaround before Winston is loaded.
To fix this, simply change the
require('./winston-workaround');
to
import './winston-workaround'
thank you very much @Kouzukii. Your solution worked correctly.
This issue is still happening as of v3.3.3. Or why is it still open?
It is still open for libraries like winston-mongodb which are depending on normalizeQuery being exposed on the instance: https://github.com/winstonjs/winston-mongodb/blob/9adea8ad3111ad02e97e004b9cdd0a0d497ba9e4/lib/winston-mongodb.js#L253
Most helpful comment
For others that have the same problem here is a temporary hack that lets
query()work as intended.