Browse Source

Use winston to provide better logs and logfiles

master
Gaëtan Renaudeau 7 years ago
parent
commit
184c49538c
  1. 1
      .eslintrc
  2. 3
      package.json
  3. 43
      src/components/ExportLogsBtn.js
  4. 3
      src/components/Onboarding/index.js
  5. 6
      src/components/SettingsPage/sections/About.js
  6. 30
      src/helpers/resolveLogsDirectory.js
  7. 2
      src/internals/index.js
  8. 184
      src/logger.js
  9. 5
      src/main/bridge.js
  10. 2
      src/renderer/init.js
  11. 4
      static/i18n/en/app.yml
  12. 137
      yarn.lock

1
.eslintrc

@ -51,6 +51,7 @@
"no-restricted-syntax": 0,
"no-prototype-builtins": 0,
"no-void": 0,
"no-lonely-if": 0,
"react/forbid-prop-types": 0,
"react/jsx-curly-brace-presence": 0,
"react/jsx-filename-extension": 0,

3
package.json

@ -106,6 +106,9 @@
"tippy.js": "^2.5.2",
"uncontrollable": "^6.0.0",
"uuid": "^3.2.1",
"winston": "^3.0.0",
"winston-daily-rotate-file": "^3.2.3",
"winston-transport": "^4.2.0",
"ws": "^5.1.1",
"zxcvbn": "^4.4.2"
},

43
src/components/ExportLogsBtn.js

@ -5,58 +5,37 @@ import fs from 'fs'
import { webFrame, remote } from 'electron'
import React, { Component } from 'react'
import { translate } from 'react-i18next'
import { connect } from 'react-redux'
import KeyHandler from 'react-key-handler'
import { createStructuredSelector, createSelector } from 'reselect'
import { accountsSelector, encodeAccountsModel } from 'reducers/accounts'
import { storeSelector as settingsSelector } from 'reducers/settings'
import { getCurrentLogFile } from 'helpers/resolveLogsDirectory'
import Button from './base/Button'
const mapStateToProps = createStructuredSelector({
accounts: createSelector(accountsSelector, encodeAccountsModel),
settings: settingsSelector,
})
class ExportLogsBtn extends Component<{
t: *,
settings: ?*,
accounts: ?*,
hookToShortcut?: boolean,
}> {
handleExportLogs = () => {
const { accounts, settings } = this.props
const logs = logger.exportLogs()
const srcLogFile = getCurrentLogFile()
const resourceUsage = webFrame.getResourceUsage()
const report = {
logger.log('exportLogsMeta', {
resourceUsage,
logs,
accounts,
settings,
date: new Date(),
release: __APP_VERSION__,
git_commit: __GIT_REVISION__,
environment: __DEV__ ? 'development' : 'production',
}
console.log(report) // eslint-disable-line no-console
const reportJSON = JSON.stringify(report)
})
const path = remote.dialog.showSaveDialog({
title: 'Export logs',
defaultPath: `ledgerlive-export-${moment().format(
'YYYY.MM.DD-HH.mm.ss',
)}-${__GIT_REVISION__ || 'unversionned'}.json`,
)}-${__GIT_REVISION__ || 'unversionned'}.log`,
filters: [
{
name: 'All Files',
extensions: ['json'],
extensions: ['log'],
},
],
})
if (path) {
fs.writeFile(path, reportJSON, err => {
if (err) {
logger.error(err)
}
})
fs.createReadStream(srcLogFile).pipe(fs.createWriteStream(path))
}
}
@ -78,10 +57,4 @@ class ExportLogsBtn extends Component<{
}
}
const WithAppData = connect(mapStateToProps)(ExportLogsBtn)
const WithoutAppData = ExportLogsBtn
const ExportLogsBtnDispatcher = ({ withAppData, ...rest }: *) =>
withAppData ? <WithAppData {...rest} /> : <WithoutAppData {...rest} />
export default translate()(ExportLogsBtnDispatcher)
export default translate()(ExportLogsBtn)

3
src/components/Onboarding/index.js

@ -25,6 +25,7 @@ import { getCurrentDevice } from 'reducers/devices'
import { unlock } from 'reducers/application'
import ExportLogsBtn from 'components/ExportLogsBtn'
import Box from 'components/base/Box'
import TriggerAppReady from '../TriggerAppReady'
@ -158,6 +159,8 @@ class Onboarding extends PureComponent<Props> {
return (
<Container>
<TriggerAppReady />
<ExportLogsBtn hookToShortcut />
{step.options.showBreadcrumb && <OnboardingBreadcrumb />}
<StepContainer>
<StepComponent {...stepProps} />

6
src/components/SettingsPage/sections/About.js

@ -5,6 +5,7 @@ import { translate } from 'react-i18next'
import type { T } from 'types/common'
import TrackPage from 'analytics/TrackPage'
import IconHelp from 'icons/Help'
import resolveLogsDirectory from 'helpers/resolveLogsDirectory'
import ExportLogsBtn from 'components/ExportLogsBtn'
import CleanButton from '../CleanButton'
@ -55,7 +56,10 @@ class SectionAbout extends PureComponent<Props> {
>
<ResetButton />
</Row>
<Row title={t('app:settings.exportLogs.title')} desc={t('app:settings.exportLogs.desc')}>
<Row
title={t('app:settings.exportLogs.title')}
desc={t('app:settings.exportLogs.desc', { logsDirectory: resolveLogsDirectory() })}
>
<ExportLogsBtn />
</Row>

30
src/helpers/resolveLogsDirectory.js

@ -0,0 +1,30 @@
// @flow
import path from 'path'
import moment from 'moment'
const resolveLogsDirectory = () => {
const { LEDGER_LOGS_DIRECTORY } = process.env
if (LEDGER_LOGS_DIRECTORY) return LEDGER_LOGS_DIRECTORY
const electron = require('electron')
return path.resolve((electron.app || electron.remote.app).getPath('userData'), 'logs')
}
export default resolveLogsDirectory
export const RotatingLogFileParameters = {
filename: 'application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
}
export const getCurrentLogFile = () =>
path.resolve(
resolveLogsDirectory(),
RotatingLogFileParameters.filename.replace(
'%DATE%',
moment().format(RotatingLogFileParameters.datePattern),
),
)

2
src/internals/index.js

@ -7,6 +7,8 @@ import sentry from 'sentry/node'
import { EXPERIMENTAL_HTTP_ON_RENDERER } from 'config/constants'
import { serializeError } from 'helpers/errors'
logger.setProcessShortName('internal')
require('../env')
process.title = 'Internal'

184
src/logger.js

@ -1,13 +1,8 @@
// @flow
/* eslint-disable no-console */
/**
* IDEA:
* logger is an alternative to use for console.log that will be used for many purposes:
* - provide useful data for debugging during dev (idea is to have opt-in env var)
* - enabled in prod to provide useful data to debug when sending to Sentry
* - for analytics in the future
*/
import winston from 'winston'
import Transport from 'winston-transport'
import resolveLogsDirectory, { RotatingLogFileParameters } from 'helpers/resolveLogsDirectory'
import {
DEBUG_NETWORK,
@ -20,51 +15,83 @@ import {
DEBUG_ANALYTICS,
} from 'config/constants'
const logs = []
require('winston-daily-rotate-file')
const MAX_LOG_LENGTH = 500
const MAX_LOG_JSON_THRESHOLD = 2000
let pname = '?'
const anonymousMode = !__DEV__
const { format } = winston
const { combine, json, timestamp } = format
const pinfo = format(info => {
info.pname = pname
return info
})
const transports = [
new winston.transports.DailyRotateFile({
dirname: resolveLogsDirectory(),
...RotatingLogFileParameters,
}),
]
function addLog(type, ...args) {
logs.push({ type, date: new Date(), args })
if (logs.length > MAX_LOG_LENGTH) {
logs.shift()
if (process.env.NODE_ENV !== 'production' || process.env.LOGS_IN_CONSOLE) {
let consoleT
if (typeof window === 'undefined') {
// on Node we want a concise logger
consoleT = new winston.transports.Console({
format: format.simple(),
})
} else {
// On Browser we want to preserve direct usage of console with the "expandable" objects
const SPLAT = Symbol.for('splat')
class CustomConsole extends Transport {
log(info, callback) {
setImmediate(() => {
this.emit('logged', info)
})
const rest = info[SPLAT]
/* eslint-disable no-console */
if (info.level === 'error') {
if (rest) {
console.error(info.message, ...rest)
} else {
console.error(info.message)
}
} else if (info.level === 'warn') {
if (rest) {
console.warn(info.message, ...rest)
} else {
console.warn(info.message)
}
} else {
if (rest) {
console.log(info.message, ...rest)
} else {
console.log(info.message)
}
}
/* eslint-enable no-console */
callback()
}
}
consoleT = new CustomConsole()
}
transports.push(consoleT)
}
const logger = winston.createLogger({
level: 'info',
format: combine(pinfo(), timestamp(), json()),
transports,
})
const anonymousMode = !__DEV__
function anonymizeURL(url) {
if (!anonymousMode) return url
return url.replace(/\/addresses\/[^/]+/g, '/addresses/<HIDDEN>')
}
const makeSerializableLog = (o: mixed) => {
if (typeof o === 'string') return o
if (typeof o === 'number') return o
if (typeof o === 'object' && o) {
try {
const json = JSON.stringify(o)
if (json.length < MAX_LOG_JSON_THRESHOLD) {
return o
}
// try to make a one level object on the same principle
const oneLevel = {}
Object.keys(o).forEach(key => {
// $FlowFixMe
oneLevel[key] = makeSerializableLog(o[key])
})
const json2 = JSON.stringify(oneLevel)
if (json2.length < MAX_LOG_JSON_THRESHOLD) {
return oneLevel
}
} catch (e) {
// This is not serializable so we will just stringify it
}
}
return String(o)
}
const logCmds = !__DEV__ || DEBUG_COMMANDS
const logDb = !__DEV__ || DEBUG_DB
const logRedux = !__DEV__ || DEBUG_ACTION
@ -75,42 +102,43 @@ const logNetwork = !__DEV__ || DEBUG_NETWORK
const logAnalytics = !__DEV__ || DEBUG_ANALYTICS
export default {
setProcessShortName: (processShortName: string) => {
pname = processShortName
},
onCmd: (type: string, id: string, spentTime: number, data?: any) => {
if (logCmds) {
switch (type) {
case 'cmd.START':
console.log(`CMD ${id}.send(`, data, ')')
logger.log('info', 'info', `CMD ${id}.send()`, { type, data })
break
case 'cmd.NEXT':
console.log(`● CMD ${id}`, data)
logger.log('info', `● CMD ${id}`, { type, data })
break
case 'cmd.COMPLETE':
console.log(`✔ CMD ${id} finished in ${spentTime.toFixed(0)}ms`)
logger.log('info', `✔ CMD ${id} finished in ${spentTime.toFixed(0)}ms`, { type })
break
case 'cmd.ERROR':
console.warn(`✖ CMD ${id} error`, data)
logger.log('warn', `✖ CMD ${id} error`, { type, data })
break
default:
}
}
addLog('cmd', type, id, spentTime, data)
},
onDB: (way: 'read' | 'write' | 'clear', name: string) => {
const msg = `📁 ${way} ${name}`
if (logDb) {
console.log(msg)
logger.log('info', msg, { type: 'db' })
}
addLog('db', msg)
},
// tracks Redux actions (NB not all actions are serializable)
onReduxAction: (action: Object) => {
if (logRedux) {
console.log(`⚛️ ${action.type}`, action)
logger.log('info', `⚛️ ${action.type}`, { type: 'action', action })
}
addLog('action', `⚛️ ${action.type}`, action)
},
// tracks keyboard events
@ -120,31 +148,27 @@ export default {
const displayEl = `${tagName.toLowerCase()}${classList.length ? ` ${classList.item(0)}` : ''}`
const msg = `⇓ <TAB> - active element ${displayEl}`
if (logTabkey) {
console.log(msg)
logger.log('info', msg, { type: 'keydown' })
}
addLog('keydown', msg)
},
websocket: (type: string, msg: *) => {
if (logWS) {
console.log(`~ ${type}:`, msg)
logger.log('info', `~ ${type}:`, msg, { type: 'ws' })
}
addLog('ws', `~ ${type}`, msg)
},
libcore: (level: string, msg: string) => {
if (logLibcore) {
console.log(`🛠 ${level}: ${msg}`)
logger.log('info', `🛠 ${level}: ${msg}`, { type: 'libcore' })
}
addLog('action', `🛠 ${level}: ${msg}`)
},
network: ({ method, url }: { method: string, url: string }) => {
const log = `➡📡 ${method} ${anonymizeURL(url)}`
if (logNetwork) {
console.log(log)
logger.log('info', log, { type: 'network' })
}
addLog('network', log)
},
networkSucceed: ({
@ -162,9 +186,8 @@ export default {
url,
)} finished in ${responseTime.toFixed(0)}ms`
if (logNetwork) {
console.log(log)
logger.log('info', log, { type: 'network-response' })
}
addLog('network-response', log)
},
networkError: ({
@ -184,9 +207,8 @@ export default {
url,
)} ${error} failed after ${responseTime.toFixed(0)}ms`
if (logNetwork) {
console.log(log)
logger.log('info', log, { type: 'network-error', status, method })
}
addLog('network-error', log)
},
networkDown: ({
@ -202,59 +224,50 @@ export default {
0,
)}ms`
if (logNetwork) {
console.log(log)
logger.log('info', log, { type: 'network-down' })
}
addLog('network-down', log)
},
analyticsStart: (id: string) => {
if (logAnalytics) {
console.log(`△ start() with user id ${id}`)
logger.log('info', `△ start() with user id ${id}`, { type: 'anaytics-start', id })
}
addLog('anaytics-start', id)
},
analyticsStop: () => {
if (logAnalytics) {
console.log(`△ stop()`)
logger.log('info', `△ stop()`, { type: 'anaytics-stop' })
}
addLog('anaytics-stop')
},
analyticsTrack: (event: string, properties: ?Object) => {
if (logAnalytics) {
console.log(`△ track ${event}`, properties)
logger.log('info', `△ track ${event}`, { type: 'anaytics-track', properties })
}
addLog('anaytics-track', `${event}`)
},
analyticsPage: (category: string, name: ?string, properties: ?Object) => {
if (logAnalytics) {
console.log(`△ page ${category} ${name || ''}`, properties)
logger.log('info', `△ page ${category} ${name || ''}`, { type: 'anaytics-page', properties })
}
addLog('anaytics-page', `${category} ${name || ''}`)
},
// General functions in case the hooks don't apply
log: (...args: any) => {
console.log(...args)
addLog('log', ...args)
logger.log('info', ...args)
},
warn: (...args: any) => {
console.warn(...args)
addLog('warn', ...args)
logger.log('warn', ...args)
},
error: (...args: any) => {
console.error(...args)
addLog('error', ...args)
logger.log('error', ...args)
},
critical: (error: Error) => {
addLog('critical', error)
console.error(error)
logger.log('error', error)
if (!process.env.STORYBOOK_ENV) {
try {
if (typeof window !== 'undefined') {
@ -263,15 +276,8 @@ export default {
require('sentry/node').captureException(error)
}
} catch (e) {
console.warn("Can't send to sentry", error, e)
logger.log('warn', "Can't send to sentry", error, e)
}
}
},
exportLogs: (): Array<{ type: string, date: Date, args: Array<any> }> =>
logs.map(({ type, date, args }) => ({
type,
date,
args: args.map(makeSerializableLog),
})),
}

5
src/main/bridge.js

@ -9,14 +9,18 @@ import path from 'path'
import logger from 'logger'
import sentry from 'sentry/node'
import user from 'helpers/user'
import resolveLogsDirectory from 'helpers/resolveLogsDirectory'
import setupAutoUpdater, { quitAndInstall } from './autoUpdate'
import { setInternalProcessPID } from './terminator'
import { getMainWindow } from './app'
logger.setProcessShortName('main')
// sqlite files will be located in the app local data folder
const LEDGER_LIVE_SQLITE_PATH = path.resolve(app.getPath('userData'), 'sqlite')
const LEDGER_LOGS_DIRECTORY = process.env.LEDGER_LOGS_DIRECTORY || resolveLogsDirectory()
let internalProcess
@ -45,6 +49,7 @@ const bootInternalProcess = () => {
internalProcess = fork(forkBundlePath, {
env: {
...process.env,
LEDGER_LOGS_DIRECTORY,
LEDGER_LIVE_SQLITE_PATH,
INITIAL_SENTRY_ENABLED: sentryEnabled,
SENTRY_USER_ID: userId,

2
src/renderer/init.js

@ -31,6 +31,8 @@ import AppError from 'components/AppError'
import 'styles/global'
logger.setProcessShortName('renderer')
const rootNode = document.getElementById('app')
const TAB_KEY = 9

4
static/i18n/en/app.yml

@ -333,8 +333,6 @@ settings: # Always ensure descriptions carry full stops (.)
changePassword: Change password
sync: Synchronize accounts
syncDesc: Resynchronize your accounts with the network.
export: Export logs
exportDesc: Exporting Ledger Live logs may be necessary for troubleshooting purposes.
softResetTitle: Clear cache
softResetDesc: Clear the Ledger Live cache to force resynchronization with the blockchain.
softReset: Clear
@ -371,7 +369,7 @@ settings: # Always ensure descriptions carry full stops (.)
desc: The account will no longer be included in your portfolio. This operation does not affect your assets. Accounts can always be re-added.
exportLogs:
title: Export logs
desc: Exporting Ledger Live logs may be necessary for troubleshooting purposes.
desc: 'Exporting Ledger Live logs may be necessary for troubleshooting purposes.'
btn: Export
password:
warning_0: Very weak

137
yarn.lock

@ -4438,16 +4438,16 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^0.5.0, color-convert@~0.5.0:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
color-convert@^1.3.0, color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.2"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
dependencies:
color-name "1.1.1"
color-convert@~0.5.0:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
color-name@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
@ -4469,6 +4469,13 @@ color-string@^1.5.2:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@0.8.x:
version "0.8.0"
resolved "https://registry.yarnpkg.com/color/-/color-0.8.0.tgz#890c07c3fd4e649537638911cf691e5458b6fca5"
dependencies:
color-convert "^0.5.0"
color-string "^0.3.0"
color@^0.11.0:
version "0.11.4"
resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
@ -4492,11 +4499,15 @@ colormin@^1.0.5:
css-color-names "0.0.4"
has "^1.0.1"
colornames@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/colornames/-/colornames-0.0.2.tgz#d811fd6c84f59029499a8ac4436202935b92be31"
colors@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
colors@^1.1.2:
colors@^1.1.2, colors@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e"
@ -4504,6 +4515,13 @@ colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
colorspace@1.0.x:
version "1.0.1"
resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.0.1.tgz#c99c796ed31128b9876a52e1ee5ee03a4a719749"
dependencies:
color "0.8.x"
text-hex "0.0.x"
columnify@~1.5.4:
version "1.5.4"
resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb"
@ -5011,6 +5029,10 @@ currently-unhandled@^0.4.1:
dependencies:
array-find-index "^1.0.1"
cycle@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
@ -5453,6 +5475,14 @@ dezalgo@^1.0.0, dezalgo@~1.0.3:
asap "^2.0.0"
wrappy "1"
diagnostics@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.0.tgz#e1090900b49523e8527be20f081275205f2ae36a"
dependencies:
colorspace "1.0.x"
enabled "1.0.x"
kuler "0.0.x"
diff@^3.2.0, diff@^3.3.1, diff@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@ -5926,6 +5956,12 @@ emotion@^9.1.2:
babel-plugin-emotion "^9.2.4"
create-emotion "^9.2.4"
enabled@1.0.x:
version "1.0.2"
resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
dependencies:
env-variable "0.0.x"
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
@ -5967,6 +6003,10 @@ env-paths@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0"
env-variable@0.0.x:
version "0.0.4"
resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.4.tgz#0d6280cf507d84242befe35a512b5ae4be77c54e"
envinfo@^5.7.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-5.10.0.tgz#503a9774ae15b93ea68bdfae2ccd6306624ea6df"
@ -6572,6 +6612,10 @@ fast-memoize@^2.2.7:
version "2.5.1"
resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.5.1.tgz#c3519241e80552ce395e1a32dcdde8d1fd680f5d"
fast-safe-stringify@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.4.tgz#4fe828718aa61dbcf9119c3c24e79cc4dea973b2"
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
@ -6612,6 +6656,10 @@ fd-slicer@~1.0.1:
dependencies:
pend "~1.2.0"
fecha@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
figgy-pudding@^3.0.0, figgy-pudding@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.1.0.tgz#a77ed2284175976c424b390b298569e9df86dd1e"
@ -6643,6 +6691,12 @@ file-loader@^1.1.11:
loader-utils "^1.0.2"
schema-utils "^0.4.5"
file-stream-rotator@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/file-stream-rotator/-/file-stream-rotator-0.2.1.tgz#0d6fea1a9a7aba25a87cfd31b6e269e44e8f0af2"
dependencies:
moment "^2.11.2"
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@ -8915,6 +8969,12 @@ klaw@^1.0.0:
optionalDependencies:
graceful-fs "^4.1.9"
kuler@0.0.x:
version "0.0.0"
resolved "https://registry.yarnpkg.com/kuler/-/kuler-0.0.0.tgz#b66bb46b934e550f59d818848e0abba4f7f5553c"
dependencies:
colornames "0.0.2"
latest-version@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
@ -9235,6 +9295,16 @@ log-update@^1.0.2:
ansi-escapes "^1.0.0"
cli-cursor "^1.0.2"
logform@^1.6.0, logform@^1.9.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/logform/-/logform-1.9.1.tgz#58b29d7b11c332456d7a217e17b48a13ad69d60a"
dependencies:
colors "^1.2.1"
fast-safe-stringify "^2.0.4"
fecha "^2.3.3"
ms "^2.1.1"
triple-beam "^1.2.0"
loglevel@^1.4.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
@ -9702,7 +9772,7 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
dependencies:
minimist "0.0.8"
moment@^2.21.0, moment@^2.22.2:
moment@^2.11.2, moment@^2.21.0, moment@^2.22.2:
version "2.22.2"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
@ -9721,7 +9791,7 @@ ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
ms@2.1.1, ms@^2.0.0:
ms@2.1.1, ms@^2.0.0, ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
@ -10364,6 +10434,10 @@ once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0:
dependencies:
wrappy "1"
one-time@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
onetime@^1.0.0:
version "1.1.0"
resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
@ -13190,7 +13264,7 @@ stable@~0.1.6:
version "0.1.8"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
stack-trace@0.0.10:
stack-trace@0.0.10, stack-trace@0.0.x:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
@ -13631,6 +13705,10 @@ test-exclude@^4.2.1:
read-pkg-up "^1.0.1"
require-main-filename "^1.0.1"
text-hex@0.0.x:
version "0.0.0"
resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-0.0.0.tgz#578fbc85a6a92636e42dd17b41d0218cce9eb2b3"
text-table@0.2.0, text-table@^0.2.0, text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -13798,6 +13876,10 @@ trim@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
triple-beam@^1.2.0, triple-beam@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
trough@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.2.tgz#7f1663ec55c480139e2de5e486c6aef6cc24a535"
@ -14657,6 +14739,45 @@ window-size@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
winston-compat@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/winston-compat/-/winston-compat-0.1.4.tgz#599b4ce807ffe728713ecc25ede3f6b89425b739"
dependencies:
cycle "~1.0.3"
logform "^1.6.0"
triple-beam "^1.2.0"
winston-daily-rotate-file@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-3.2.3.tgz#9f80e7a421ab32b073c1217bae62e762001197d6"
dependencies:
file-stream-rotator "^0.2.1"
semver "^5.5.0"
triple-beam "^1.3.0"
winston-compat "^0.1.4"
winston-transport "^4.2.0"
winston-transport@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.2.0.tgz#a20be89edf2ea2ca39ba25f3e50344d73e6520e5"
dependencies:
readable-stream "^2.3.6"
triple-beam "^1.2.0"
winston@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/winston/-/winston-3.0.0.tgz#1f0b24a96586798bcf0cd149fb07ed47cb01a1b2"
dependencies:
async "^2.6.0"
diagnostics "^1.0.1"
is-stream "^1.1.0"
logform "^1.9.0"
one-time "0.0.4"
readable-stream "^2.3.6"
stack-trace "0.0.x"
triple-beam "^1.3.0"
winston-transport "^4.2.0"
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"

Loading…
Cancel
Save