Winston: Die Übergabe mehrerer Parameter an Protokollierungsfunktionen verhält sich nicht wie erwartet

Erstellt am 6. Aug. 2018  ·  43Kommentare  ·  Quelle: winstonjs/winston

Bitte erzählen Sie uns von Ihrer Umgebung:

  • _ winston Version?_

    • [ ] winston@2

    • [x] winston@3

  • _ node -v Ausgaben:_ v8.11.3
  • _Betriebssystem?_ macOS
  • _Sprache?_ Flow ES6/7

Was ist das Problem?


Mit 3.xx:

const winston = require('winston')

const logger = winston.createLogger({
    transports: [new winston.transports.Console()]
})

logger.info('test log', 'with a second parameter')

Ausgänge:

{"level":"info","message":"test log"}

Mit 2.xx:

const winston = require('winston')

const logger = new winston.Logger({
    transports: [new winston.transports.Console()]
})

logger.info('test log', 'with a second parameter')

Ausgänge:

info: test log with a second parameter

Was erwarten Sie stattdessen?


Es sollte ausgegeben werden:

{"level":"info","message":"test log with a second parameter"}
important

Hilfreichster Kommentar

Für uns ist dies eine RIESIGE bahnbrechende Veränderung. Wenn es beabsichtigt ist, sollte es in https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md beschrieben werden

Alle 43 Kommentare

Ich bin heute auf das gleiche Problem gestoßen. Ich glaube, es ist ein Fehler, da die Upgrade-Dokumentation auch ein Beispiel wie dieses hier enthält :

logger.info('transaction ok', { creditCard: 123456789012345 });

Um dies zu umgehen, können Sie derzeit eine Funktion erstellen, die die Argumente analysiert, bevor sie an winston übergeben wird

@mulligan121 Okay, aber ich möchte nicht jede Log-Anweisung in meiner Codebasis ersetzen ...

@indexzero Ist das unter Ihrem Radar? Ich denke, dies ist eine große bahnbrechende Änderung. Es verhindert tatsächlich den Wechsel von 2.x auf 3.x, da wir jeden Log-Eintrag ändern müssen

Temporäre Problemumgehung:

const wrapper = ( original ) => {
    return (...args) => original(args.join(" "));
};

winstonLogger.error = wrapper(winstonLogger.error);
winstonLogger.warn = wrapper(winstonLogger.warn);
winstonLogger.info = wrapper(winstonLogger.info);
winstonLogger.verbose = wrapper(winstonLogger.verbose);
winstonLogger.debug = wrapper(winstonLogger.debug);
winstonLogger.silly = wrapper(winstonLogger.silly);

Für uns ist dies eine RIESIGE bahnbrechende Veränderung. Wenn es beabsichtigt ist, sollte es in https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md beschrieben werden

Nach einigen weiteren Untersuchungen habe ich also festgestellt, dass Sie den Splat-Formatierer benötigen, damit mehrere Argumente gedruckt werden können. Ich dachte, das wäre nur für die Argumentinterpolation (dh Sachen mit %s usw.), aber es scheint, dass Sie es nur brauchen, um logger.info("something", value) zu tun.

Aber das ist immer noch ein bisschen seltsam für mich - ich bekomme etwas, das wie JSON in der Ausgabe mit einem Schlüssel "meta" aussieht, obwohl ich kein JSON-Format verwende:

logger.info('Test: %s', 1, 2, 3, 4);

Produziert:

info: Test: 1 {"meta":[2,3,4]}

Selbst das Beispiel in den Beispielen liefert nicht das, was es verspricht:

https://github.com/winstonjs/winston/blob/master/examples/interpolation.js#L20 -L21

info: test message first, second {"meta":{"number":123}}

Ich habe es mit etwas in dieser Richtung gelöst:

const { version } = require('../package');

const { createLogger, format, transports } = require('winston');
const { combine, timestamp, colorize, label, printf, align } = format;
const { SPLAT } = require('triple-beam');
const { isObject } = require('lodash');

function formatObject(param) {
  if (isObject(param)) {
    return JSON.stringify(param);
  }
  return param;
}

// Ignore log messages if they have { private: true }
const all = format((info) => {
  const splat = info[SPLAT] || [];
  const message = formatObject(info.message);
  const rest = splat.map(formatObject).join(' ');
  info.message = `${message} ${rest}`;
  return info;
});

const customLogger = createLogger({
  format: combine(
    all(),
    label({ label: version }),
    timestamp(),
    colorize(),
    align(),
    printf(info => `${info.timestamp} [${info.label}] ${info.level}: ${formatObject(info.message)}`)
  ),
  transports: [new transports.Console()]
});

Hier ist eine gängige Problemumgehung, um mehrere Parameter zuzulassen:
https://github.com/rooseveltframework/roosevelt/blob/master/lib/tools/logger.js#L29

Bezüglich:
https://github.com/winstonjs/winston/issues/1377

Es gibt einfach zu viele Dinge, die nicht gleich funktionieren.

Hallo, gibt es hier Updates? Danke.

Wartet auch auf die richtige Methode, um console.log(...args) in Winston zu emulieren ...

Wir haben eine Reihe der Kanten-/Eckfälle um splat und meta in 3.2.0 behoben, aber es scheint, dass dies immer noch ein Problem ist (siehe: https://github.com /winstonjs/winston/pull/1576 für CHANGELOG.md ).

Stellt sicher, dass dies in 3.3.0 gehandhabt wird. Danke für eure Geduld Leute.

Dies war ein Workaround für mich:

'use strict';

const { createLogger, format, transports } = require('winston');
const { SPLAT } = require('triple-beam');

const { combine, timestamp, label, printf, colorize } = format;

const formatObject = (param) => {
  if (typeof param === 'string') {
    return param;
  }

  if (param instanceof Error) {
    return param.stack ? param.stack : JSON.stringify(param, null, 2);
  }

  return JSON.stringify(param, null, 2);
};

const logFormat = printf((info) => {
  const { timestamp: ts, level, message } = info;
  const rest = info[SPLAT] || [];
  const msg = info.stack ? formatObject(info.stack) : formatObject(message);
  let result = `${ts} ${level}: ${msg}`;

  if (rest.length) {
    result += `\n${rest.map(formatObject).join('\n')}`;
  }

  return result;
});

const logger = createLogger({
  format: combine(
    label({ label: 'app' }),
    timestamp(),
    logFormat,
  ),
  transports: [
    new transports.Console({
      format: combine(colorize()),
      handleExceptions: true,
    }),
  ],
  exceptionHandlers: [
    new transports.File({ filename: 'exceptions.log' }),
  ],
});

Wenn ich versuche, mich mit Argumenten anzumelden, bekomme ich eine seltsame Ausgabe
var s = "Hello" log.info("asdasda", s)

Ausgabe erhalten

{"0":"H","1":"e","2":"l","3":"l","4":"o","service":"XXXX","level":"info","message":"asdasda","timestamp":"2019-04-15 13:58:51"}

Ich habe den normalen Schnellstartcode verwendet

Eine Sache die mir aufgefallen ist ist folgendes:

  • habe einen Logger mit 2 Transporten (Konsole und rotierende Datei)
  • Beide verwenden das Splat-Format
  • Der Aufruf der Transformationsfunktion von splat für den ersten Transport löscht das Array, das auf info unter dem SPLAT-Symbol gespeichert ist
  • Beim Aufruf der Transformationsfunktion von splat für den zweiten Transport ist das SPLAT-Array leer und somit werden die zusätzlichen Argumente nicht mehr protokolliert

Hoffe das kann/wird behoben

Hinweis: Getestet mit der neuesten veröffentlichten Version von Winston, ein kurzer Blick auf den Code scheint darauf hinzudeuten, dass es in Master immer noch so ist (was anscheinend andere Fixes enthält).

Einige Verbesserungen gegenüber @luislobo ‚s Lösung 👏

  • Nachricht ignorieren, wenn sie Splat-Stil enthält, dh %s %d or %j für Nachrichten wie logger.info(`hello %s`,'world')
  • Formatierer neu geordnet, damit Kolorieren an erster Stelle steht https://github.com/winstonjs/winston#colorizing -standard-logging-levels
  • twise formateObject in printf
  • trimEnd wenn zusätzliche Argumente im Logger nicht bereitgestellt werden
const { version } = require('../package');

const { createLogger, format, transports } = require('winston');
const { combine, timestamp, colorize, label, printf, align } = format;
const { SPLAT } = require('triple-beam');
const { isObject,trimEnd } = require('lodash');

function formatObject(param) {
  if (isObject(param)) {
    return JSON.stringify(param);
  }
  return param;
}

const all = format((info) => {
  const splat = info[SPLAT] || []

    const isSplatTypeMessage =
        typeof info.message === 'string' &&
        (info.message.includes('%s') || info.message.includes('%d') || info.message.includes('%j'))
    if (isSplatTypeMessage) {
        return info
    }
    const message = formatObject(info.message)
    const rest = splat
        .map(formatObject)
        .join(' ')
    info.message = trimEnd(`${message} ${rest}`)
    return info
});

const customLogger = createLogger({
  format: combine(
    colorize(),
    all(),
    label({ label: version }),
    timestamp(),
    align(),
    printf(info => `${info.timestamp} [${info.label}] ${info.level}: ${info.message}`)
  ),
  transports: [new transports.Console()]
});

Irgendwelche weiteren Updates dazu, die ich möglicherweise vermisse? Es scheint, als ob es ziemlich starke Unterstützung dafür gibt, dass diese Funktion erneut hinzugefügt wird, aber die letzte Zusage dazu liegt fast 6 Monate zurück.

Hallo zusammen, riesiger Bumper und Showstopper, der versucht, auf die 3.X zu migrieren, wird die 2.x wahrscheinlich eine Weile behalten.

Ein bisschen enttäuscht :(

Das hat bei mir funktioniert:

const { format, createLogger, transports } = require('winston');
const jsonStringify = require('fast-safe-stringify');

const logLikeFormat = {
  transform(info) {
    const { timestamp, label, message } = info;
    const level = info[Symbol.for('level')];
    const args = info[Symbol.for('splat')];
    const strArgs = args.map(jsonStringify).join(' ');
    info[Symbol.for('message')] = `${timestamp} [${label}] ${level}: ${message} ${strArgs}`;
    return info;
  }
};

const debugFormat = {
  transform(info) {
    console.log(info);
    return info;
  }
};

const logger = createLogger({
  format: format.combine(
    // debugFormat, // uncomment to see the internal log structure
    format.timestamp(),
    format.label({ label: 'myLabel' }),
    logLikeFormat,
    // debugFormat, // uncomment to see the internal log structure
  ),
  transports: [
    new transports.Console()
  ]
});


logger.info('foo', 'bar', 1, [2, 3], true, { name: 'John' });

was ergibt: 2019-07-04T21:30:08.455Z [myLabel] info: foo "bar" 1 [2,3] true {"name":"John"}

Grundsätzlich legt format.combine eine Pipeline für ein info Objekt fest. Für jede Formatfunktion wird transform aufgerufen und die letzte Protokollnachricht sollte in info[Symbol.for('message')]
hoffe das hilft

Ich wollte eine Lösung, die %d , %o usw. unterstützt, aber standardmäßig immer noch alle Restargumente enthält, sodass logger.info('hello %d %j', 42, {a:3}, 'some', 'more', 'arguments') wie folgt gerendert wird:

hello 42 {"a": 3} some more arguments

Meine Lösung dafür endete mit dem splat Symbol, aber dem manuellen Aufrufen von util.format() direkt aus printf , das standardmäßig alle Restargumente enthält:

const {format} = require('util');
const winston = require('winston');
const {combine, timestamp, printf} = winston.format;
const SPLAT = Symbol.for('splat');

const transport = new winston.transports.Console({
    format: combine(
        timestamp(),
        printf(({timestamp, level, message, [SPLAT]: args = []}) =>
            `${timestamp} - ${level}: ${format(message, ...args)}`)
    )
})

Wenn Sie printf nicht möchten, können Sie natürlich stattdessen eine Transformation hinzufügen, die die Argumente einfach in info.message , und dann das Endergebnis nach Ihren Wünschen formatieren:

format: combine(
  {
    transform(info) {
      const {[SPLAT]: args = [], message} = info;

      info.message = format(message, ...args);

      return info;
    }
  },
  simple()
)  

Das Problem bei der Verwendung von format.splat() besteht darin, dass es die passenden Argumente verbraucht, aber den Rest scheinbar wegwirft. Indem ich util.format() selbst aufrufe, kann ich dieses Verhalten überschreiben.

Gleiches Problem, gibt es diesbezüglich ein Update? Ich liebe Winston, aber es macht mich verrückt, wenn ich nicht alle an den Logger übergebenen Argumente ausgeben kann, was ich mit console.log() tun kann.

@fr1sk Hast du meine obige Formatierung ausprobiert? Es ergibt ein console.log() ähnliches Verhalten (die console.log() Implementierung des Knotens verwendet intern util.format() afaik).

Es ist enttäuschend, dass dieses Problem immer noch nicht behoben wurde und mein damit verbundenes Problem behoben wurde.
Ich arbeite mit vielen verschiedenen Teams zusammen und alle teilen die Frustration, dass ich bei der Migration auf v3 frühere DX verloren habe.

Ich habe einen ganzen Tag damit verbracht, Dinge auszuprobieren.
Die obigen Lösungen waren nah dran, aber mir fehlten die Einfärbung und der Zeilenumbruch von zusätzlichen Argumenten.

IMO, die Anmeldung an der Konsole sollte angenehm sein.
Hier ist mein Versuch, es zu verwirklichen...

v2-Setup zum Vergleich

const winston = require('winston');
const chalk = require('chalk');

const logger = new winston.Logger({
  transports: [
    new winston.transports.Console({
      level: 'info',
      colorize: true,
      prettyPrint: true,
      timestamp: true
    })
  ]
});

logger.info({ one: 1, two: 2, three: 3 });
logger.info(chalk.blue('[TEST]:'), { one: 1, two: 2, three: 3 }, [4, 5, 6]);
logger.info(chalk.blue('[TEST]:'), null, undefined, 'one', 2, { 3: 3, 4: '4' });
logger.info(chalk.blue('[TEST]:'), chalk.yellow('Bombastic'), () => {}, /foo/);
logger.error(chalk.blue('[ERR]:'), new Error('Error number 1'));
logger.error(new Error('Error number 2'));

Winston2

v3-Setup

const { createLogger, format, transports } = require('winston');
const { inspect } = require('util');
const chalk = require('chalk');
const hasAnsi = require('has-ansi');

function isPrimitive(val) {
  return val === null || (typeof val !== 'object' && typeof val !== 'function');
}
function formatWithInspect(val) {
  const prefix = isPrimitive(val) ? '' : '\n';
  const shouldFormat = typeof val !== 'string' || !hasAnsi(val);

  return prefix + (shouldFormat ? inspect(val, { depth: null, colors: true }) : val);
}

const logger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp(),
    format.errors({ stack: true }),
    format.colorize(),
    format.printf(info => {
      const msg = formatWithInspect(info.message);
      const splatArgs = info[Symbol.for('splat')] || [];
      const rest = splatArgs.map(data => formatWithInspect(data)).join(' ');

      return `${info.timestamp} - ${info.level}: ${msg} ${rest}`;
    })
  ),
  transports: [new transports.Console()]
});

logger.info({ one: 1, two: 2, three: 3 });
logger.info(chalk.blue('[TEST]:'), { one: 1, two: 2, three: 3 }, [4, 5, 6]);
logger.info(chalk.blue('[TEST]:'), null, undefined, 'one', 2, { 3: 3, 4: '4' });
logger.info(chalk.blue('[TEST]:'), chalk.yellow('Bombastic'), () => {}, /foo/);
logger.error(chalk.blue('[ERR]:'), new Error('Error number 1'));
logger.error(new Error('Error number 2'));

Winston3

Es gibt viele Dinge zu handhaben, von denen einige

  • Ein objektähnlicher Wert als erstes Argument
  • Mehrere Argumente mit gemischten Werten
  • Strings mit ANSI-Escape-Codes, zB mit chalk
  • Esoterische Werte wie Function und RegEx
  • Ein Fehler als erstes Argument oder irgendwo danach
  • Sollte zusammen mit anderen Formatierern immer noch gut funktionieren

Aktuelle Fehler bei dieser Lösung

  • Die Übergabe eines Fehlers als erstes Argument druckt den Stack Trace nicht

    • Dies liegt daran, dass info.message nur eine Zeichenfolge ist und sich der Stapeltrakt in der Eigenschaft stack

  • Die Übergabe eines Objekts mit einer message Eigenschaft als erstes Argument gibt nur message , alle anderen Eigenschaften werden verworfen

    • Gleicher Grund wie oben

  • Die Übergabe eines Fehlers als zweites Argument verkettet die Fehlermeldung irgendwie über info.message (was normalerweise der Wert des ersten Arguments ist), was dazu führt, dass die Fehlermeldung zweimal angezeigt wird

    • Nachverfolgt in https://github.com/winstonjs/winston/issues/1660

    • Dies ist eigentlich Teil der README:

      > HINWEIS: Jede { message }-Eigenschaft in einem bereitgestellten Metaobjekt wird automatisch mit jeder bereits bereitgestellten Nachricht verkettet: Zum Beispiel wird im Folgenden 'world' mit 'hello' verkettet:

Herumspielen mit dem errors Formatierer hat nicht geholfen.

Positive Verbesserungen

  • Das Protokollieren von primitiven Werten wird jetzt verschönert
  • Beim Protokollieren mehrerer objektähnlicher Werte wird jetzt eine neue Zeile dazwischen eingefügt
  • Das Loggen eines Arrays wird jetzt verschönert, anstatt wie ein Objekt mit Indexschlüsseln auszusehen

Bearbeiten:

Wir können mit den Fehlern bei der Formatierung umgehen, aber es ist hackig:

function formatWithInspect(val) {
+ if (val instanceof Error) {
+   return '';
+ }

  const prefix = isPrimitive(val) ? '' : '\n';
  const shouldFormat = typeof val !== 'string' || !hasAnsi(val);

  return prefix + (shouldFormat ? inspect(val, { depth: null, colors: true }) : val);
}

...
    format.printf((info) => {
      const msg = formatWithInspect(info.message);
      const splatArgs = info[Symbol.for('splat')] || [];
      const rest = splatArgs.map((data) => formatWithInspect(data)).join(' ');
+    const stackTrace = info.stack ? `\n${info.stack}` : '';

      return `${info.timestamp} - ${info.level}: ${msg} ${rest}${stackTrace}`;
    })
...

bei mir funktioniert es mit info[Symbol.for('splat')]

const logger = winston.createLogger({
    level: 'debug',
    transports: [
        ...
    ],
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.printf((info: any) => {
            const timestamp = info.timestamp.trim();
            const level = info.level;
            const message = (info.message || '').trim();
            const args = info[Symbol.for('splat')];
            const strArgs = (args || []).map((arg: any) => {
                return util.inspect(arg, {
                    colors: true
                });
            }).join(' ');
            return `[${timestamp}] ${level} ${message} ${strArgs}`;
        })
    )
});

Ich verstehe, dass Hauptversionen grundlegende Änderungen einführen, aber meine Güte...

Keine der Lösungen gab mir das gleiche Verhalten wie winston v2.
Lösungen von @henhal und @yamadashy haben beide das gleiche Problem: Der Nachrichtenwert wird als String
logger.debug(err) Protokollnachricht erstellen:

debug:  Error: ETIMEDOUT

während logger.debug('anystringhere', err) erstellt:

debug:  anystringhereError: ETIMEDOUT { RequestError: Error: ETIMEDOUT
    at new RequestError (/path/to/node_modules/request-promise-core/lib/errors.js:14:15)
 <the rest of full error stack here>

Das zweite Problem ist, dass die zusätzlichen Argumente bei der Verwendung mit info level unterdrückt werden - Winston v3 scheint dies vor der Formatierung anders zu handhaben.

Drittes Problem ist das fehlende Leerzeichen zwischen 2 Nachrichten (beachte "anystringhereError").

Meine aktuelle v3-Logger-Konfiguration:

const { format } = require('util');
const winston = require("winston");

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug'
      format: winston.format.combine(
          winston.format.colorize(),
          winston.format.align(),
          winston.format.printf(
              ({level, message, [Symbol.for('splat')]: args = []}) => `${level}: ${format(message, ...args)}`
          )
      )
    }),
  ]
});
module.exports = logger;

Ich hatte genug davon und werde nur mit diesem zurück zu Winston v2 wechseln:

const Winston = require("winston");

const logger = new Winston.Logger({
  transports: [
    new Winston.transports.Console({
      level: 'debug',
      handleExceptions: true,
      json: false,
      colorize: true,
    })
  ],
});
module.exports = logger;

Diese v2-Konfiguration weist die oben genannten Probleme nicht auf.

Ich möchte mein Winston-Setup teilen:

const util = require('util');
const { createLogger, format, transports } = require('winston');
const { combine, colorize, timestamp, printf, padLevels} = format;

const myFormat = printf(({ level, message, label, timestamp, ...rest }) => {
    const splat = rest[Symbol.for('splat')];
    const strArgs = splat ? splat.map((s) => util.formatWithOptions({ colors: true, depth: 10 }, s)).join(' ') : '';
    return `${timestamp}  ${level}  ${util.formatWithOptions({ colors: true, depth: 10}, message)} ${strArgs}`;
});

const logger = createLogger({
    level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
    format: combine(
        colorize(),
        timestamp({
            format: 'YYYY-M-DD HH:mm:ss',
        }),
        padLevels(),
        myFormat
    ),
    transports: [new transports.Console()],
});

logger.info('test info');
logger.error('test error');
logger.debug('test debug');

image

Hier ist eine gängige Problemumgehung, um mehrere Parameter zuzulassen:
https://github.com/rooseveltframework/roosevelt/blob/master/lib/tools/logger.js#L29

hier ist der aktualisierte Link zur vorgeschlagenen Lösung
https://github.com/rooseveltframework/roosevelt/blob/0.13.0/lib/tools/logger.js

Meins ist eine Variation von @alexilyaev großartigen Vorschlägen:

const { omit } = require('lodash');
const hasAnsi = require('has-ansi');

function isPrimitive(val) {
  return val === null || (typeof val !== 'object' && typeof val !== 'function');
}
function formatWithInspect(val) {
  if (val instanceof Error) {
    return '';
  }

  const shouldFormat = typeof val !== 'string' && !hasAnsi(val);
  const formattedVal = shouldFormat
    ? inspect(val, { depth: null, colors: true })
    : val;

  return isPrimitive(val) ? formattedVal : `\n${formattedVal}`;
}

// Handles all the different log formats for console
function getDomainWinstonLoggerFormat(format) {
  return format.combine(
    format.timestamp(),
    format.errors({ stack: true }),
    format.colorize(),
    format.printf((info) => {
      const stackTrace = info.stack ? `\n${info.stack}` : '';

      // handle single object
      if (!info.message) {
        const obj = omit(info, ['level', 'timestamp', Symbol.for('level')]);
        return `${info.timestamp} - ${info.level}: ${formatWithInspect(obj)}${stackTrace}`;
      }

      const splatArgs = info[Symbol.for('splat')] || [];
      const rest = splatArgs.map(data => formatWithInspect(data)).join('');
      const msg = formatWithInspect(info.message);

      return `${info.timestamp} - ${info.level}: ${msg}${rest}${stackTrace}`;
    }),
  );
}

für Protokolle wie:

logger.info({
    joe: 'blow',
  });
  logger.info('Single String');
  logger.info('With Func ', () => {}, /foo/);
  logger.info('String One ', 'String Two');
  logger.info('String One ', 'String Two ', 'String Three');
  logger.info('Single Object ', {
    test: 123,
  });
  logger.info(
    'Multiple Objects ',
    {
      test: 123,
    },
    {
      martin: 5555,
    },
  );
  logger.error('Error: ', new Error('Boom!'));

Es wird so ausgegeben - was für alle meine Szenarien gut ist:

Screen Shot 2020-02-06 at 10 54 31 pm

Hey, ich fange mit Winston an, habe noch nie v2 verwendet, also bin ich auf v3.2.1

Ich habe versucht, einfach zu tun:

import winston, { format } from 'winston';
winston.format(format.combine(format.splat(), format.simple()));

winston.info('buildFastify dataPath %s', opts.dataPath);

Und hoffen, dass die String-Interpolation funktioniert; aber nein.

{"level":"info","message":"buildFastify dataPath %s"}

Als ich erwartet hatte

{"level":"info","message":"buildFastify dataPath /My/Data/Path"}

Dieses Problem ist irgendwie dasselbe? Oder bin ich gezwungen, stattdessen die Funktion logger.log('info', .....) verwenden?

Bearbeiten

Event versucht, dies zu versuchen, funktioniert nicht.

  winston.log('info', 'buildFastify dataPath %s', opts.dataPath);

Ausgang:

{"level":"info","message":"buildFastify dataPath %s"}

Danke an die, die die obigen Vorschläge gepostet haben.
Verdammt, ich habe es eines Tages weggeworfen, nur um Winston 3 in mein Projekt zu integrieren :/

Dieser hat mich heute getroffen - mir wurde klar, dass mein schicker neuer Logger alle meine ...rest Argumente warf. Dies funktioniert möglicherweise nicht für jeden oder jeden Anwendungsfall, aber in meinem Fall fand ich es akzeptabel, einfach alles, was ich wollte, als Array zu protokollieren. Es ist nicht das schönste, aber es ist leichter als einige der [sehr cleveren] Workarounds, die mehr Code erfordern. Hoffe das hilft jemand anderem!

logger.info(["Something happened!", foo, bar]);

Wirklich ärgerlich, dass sie sich entschieden haben, eine so große Änderung vorzunehmen und sie NOCH NICHT im Migrationshandbuch oder in der Dokumentation erwähnt haben.

Unabhängig davon wollte ich meine Lösung teilen, die ich ziemlich kompakt fand und folgte, wie node js console.log mit util.format implementiert

const winstonLogger= createLogger(...);

const writeLogType = (logLevel) => {
    return function () {
        const args = Array.from(arguments);
        winstonLogger[logLevel](util.format(...args));
    };
};

const logger = {
    silly: writeLogType('silly'),
    debug: writeLogType('debug'),
    verbose: writeLogType('verbose'),
    info: writeLogType('info'),
    warn: writeLogType('warn'),
    error: writeLogType('error'),
};

Ich möchte mich einmischen und bitten, dass diese Funktion zum Kern von Winston hinzugefügt wird. Derzeit verwende ich den benutzerdefinierten Formatierer mit splat , um diese Funktionalität zu erreichen, die sich ehrlich gesagt sehr hackig anfühlt. Es wäre schön, Funktionen zu haben, die console.log

Irgendwelche Updates?

Neben den oben genannten Verhaltensweisen für v3 möchte ich auch Folgendes hinzufügen:

logger.info('param 1', { propInJson1: 'propInJson 1', propInJson2: 'propInJson 2' });

wird das produzieren

{"propInJson1":"propInJson 1","propInJson2":"propInJson 2","level":"info","message":"param 1"}

die von mir verwendete Version: (v3.2.1)
Die Konfigurationen:

winstonLogger.add(new winston.transports.Console());

Ich verstehe immer noch nicht, wie man mehrere Werte in Winston ausgibt.

Ich wollte nur console.log('Hello', var1, '!') durch logger.log('Hello', var1, '!') ersetzen.

Um ehrlich zu sein, führt der Versuch, Winston zu verwenden, immer zu viel Zeitverschwendung und überraschenden Problemen bei der Protokollierung.

Wirklich ärgerlich, dass sie sich entschieden haben, eine so große Änderung vorzunehmen und sie NOCH NICHT im Migrationshandbuch oder in der Dokumentation erwähnt haben.

Unabhängig davon wollte ich meine Lösung teilen, die ich ziemlich kompakt fand und folgte, wie node js console.log mit util.format implementiert

const winstonLogger= createLogger(...);

const writeLogType = (logLevel) => {
    return function () {
        const args = Array.from(arguments);
        winstonLogger[logLevel](util.format(...args));
    };
};

const logger = {
    silly: writeLogType('silly'),
    debug: writeLogType('debug'),
    verbose: writeLogType('verbose'),
    info: writeLogType('info'),
    warn: writeLogType('warn'),
    error: writeLogType('error'),
};

Verwenden Sie außerdem util.formatWithOptions({ colors: true }, ...args); , um eine farbige Druckausgabe wie bei normalen console.log

Das funktioniert bei mir. combineMessageAndSplat kombiniert Nachricht und Splat mit util.format

const winston = require("winston");
const util    = require('util');

const combineMessageAndSplat = () => {
    return {transform: (info, opts) => {
      //combine message and args if any
      info.message =  util.format(info.message, ...info[Symbol.for('splat')]  ||  [] )
      return info;
    }
  }
}

const logger = winston.createLogger({
  format:
    winston.format.combine(
      combineMessageAndSplat(),
      winston.format.simple()
    )
});

logger.add(new winston.transports.Console({
    level: 'info'
  })
);

logger.info("string");          // info: string
logger.info({a:1,b:[{c:[1]}]}); // info: { a: 1, b: [ { c: [Array] } ] }
logger.info("1","2",{a:1});     // info: 1 2 { a: 1 }
logger.info([{},""]);           // info: [ {}, '' ]
logger.error(new Error());      // error: Error ...    at Object.<anonymous> 

Ich musste mich an die console.*-Methoden halten, die sich an allem oben orientierten, und ...

  • Standard-Konsolenmethoden (sie werden standardmäßig eingefärbt) für chrome-dev-tools
  • Konsolenausgabe des Elektronenterminals (standardmäßig auch farbig)
  • in eine Datei schreiben

Aber: Die Dateiausgabe sollte Objektdetails zeigen.

Also landete ich bei:

// make File and FileList parseable // from: https://stackoverflow.com/a/51939522/1644202
File.prototype.toObject = function () {
    return Object({
        name: String(this.name),
        path: String(this.path),
        lastModified: parseInt(this.lastModified),
        lastModifiedDate: String(this.lastModifiedDate),
        size: parseInt(this.size),
        type: String(this.type)
    });
};

FileList.prototype.toArray = function () {
    return Array.from(this).map(function (file) {
        return file.toObject()
    });
};

// this fixes: winston console transport to use the original console functions and all the colorization/folding/etc that comes with it
const Transport = require('winston-transport');
class WebDeveloperConsole extends Transport {
    constructor(opts) {
        super(opts);
    }

    log(info, callback) {
        (window.console[info.level] || window.console.log).apply(window.console, [info.timestamp, ...info.message]);
        callback();
    }
};

// Electron app console output
class AppConsole extends Transport {
    constructor(opts) {
        super(opts);

        const { remote } = require('electron');
        this.electronConsole = remote.getGlobal('console');
    }

    log(info, callback) {
        (this.electronConsole[info.level] || this.electronConsole.log).apply(this.electronConsole, [info.timestamp, ...info.message]);
        callback();
    }
};

const util = require('util');
const {
    createLogger,
    transports,
    format
} = require('winston');

let logger = createLogger({
    level: 'trace',
    levels: {
        error: 0,
        warn: 1,
        info: 2,
        //http: 3,   no console.* methods
        //verbose: 4,
        debug: 3,
        trace: 4
    },

    format: format.combine(
        format.prettyPrint(),
        format.timestamp({
            format: 'DD-MM-YYYY hh:mm:ss A'
        }),

        {
            transform(info) {
                const { timestamp, message } = info;
                const level = info[Symbol.for('level')];
                const args = [message, ...(info[Symbol.for('splat')] || [])];  // join the args back into one arr
                info.message = args;  // for all custom transports (mainly the console ones)

                let msg = args.map(e => {
                    if (e.toString() == '[object FileList]')
                        return util.inspect(e.toArray(), true, 10);
                    else if (e.toString() == '[object File]')
                        return util.inspect(e.toObject(), true, 10);
                    else if (e.toString() == '[object Object]') {
                        return util.inspect(e, true, 5);
                    }
                    else if (e instanceof Error)
                        return e.stack
                    else
                        return e;
                }).join(' ');

                info[Symbol.for('message')] = `${timestamp} - ${level}: ${msg}`; // for inbuild transport / file-transport

                return info;
            }
        },
    ),
    transports: [
        //new transports.Console(),
        new WebDeveloperConsole(),
        new AppConsole(),
        ...
    ],
    ...
});

@indexzero Haben Sie sich gefragt, ob Sie das wollten ?

Ich erkunde Winston, um es in meinem Projekt zu verwenden, und frage mich jetzt, ob es sich lohnt, das Risiko einzugehen, da dieses Thema seit mehr als 2 Jahren offen ist. für mich scheint dies eine grundlegende Funktion für jedes Logging-Framework zu sein

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen