Winston: 3.0.0 winston.query throws exception for File Transport

Created on 6 Nov 2017  路  12Comments  路  Source: winstonjs/winston

The Functions Transport.prototype.normalizeQuery, Transport.prototype.formatResults and common.clone were removed in 3.0.0, so query will throw an unhandled exception.

bug good first issue help wanted winston-file

Most helpful comment

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;
};

All 12 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JaehyunLee-B2LiNK picture JaehyunLee-B2LiNK  路  3Comments

xungwoo picture xungwoo  路  3Comments

mohanen picture mohanen  路  4Comments

Buzut picture Buzut  路  3Comments

KingRial picture KingRial  路  3Comments