Browse Source

Merge pull request #1047 from gre/better-logger-system

Better logger system, fix race condition, smaller log exports
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
108e3fc302
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      src/components/ExportLogsBtn.js
  2. 12
      src/helpers/pname.js
  3. 16
      src/helpers/resolveLogsDirectory.js
  4. 2
      src/internals/index.js
  5. 1
      src/logger/logger-storybook.js
  6. 56
      src/logger/logger.js
  7. 3
      src/main/bridge.js
  8. 2
      src/renderer/init.js
  9. 4
      src/sentry/install.js

31
src/components/ExportLogsBtn.js

@ -6,22 +6,17 @@ import { webFrame, remote } from 'electron'
import React, { Component } from 'react' import React, { Component } from 'react'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import KeyHandler from 'react-key-handler' import KeyHandler from 'react-key-handler'
import { getCurrentLogFile } from 'helpers/resolveLogsDirectory'
import Button from './base/Button' import Button from './base/Button'
function copyFile(source, target) { function writeToFile(file, data) {
const rd = fs.createReadStream(source)
const wr = fs.createWriteStream(target)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
rd.on('error', reject) fs.writeFile(file, data, error => {
wr.on('error', reject) if (error) {
wr.on('finish', resolve) reject(error)
rd.pipe(wr) } else {
}).catch(error => { resolve()
// $FlowFixMe }
rd.destroy() })
wr.end()
throw error
}) })
} }
@ -30,9 +25,7 @@ class ExportLogsBtn extends Component<{
hookToShortcut?: boolean, hookToShortcut?: boolean,
}> { }> {
export = async () => { export = async () => {
const srcLogFile = await getCurrentLogFile()
const resourceUsage = webFrame.getResourceUsage() const resourceUsage = webFrame.getResourceUsage()
const ext = srcLogFile.match(/[.]log[.]gz$/) ? 'log.gz' : 'log'
logger.log('exportLogsMeta', { logger.log('exportLogsMeta', {
resourceUsage, resourceUsage,
release: __APP_VERSION__, release: __APP_VERSION__,
@ -44,16 +37,18 @@ class ExportLogsBtn extends Component<{
title: 'Export logs', title: 'Export logs',
defaultPath: `ledgerlive-export-${moment().format( defaultPath: `ledgerlive-export-${moment().format(
'YYYY.MM.DD-HH.mm.ss', 'YYYY.MM.DD-HH.mm.ss',
)}-${__GIT_REVISION__ || 'unversionned'}.${ext}`, )}-${__GIT_REVISION__ || 'unversionned'}.json`,
filters: [ filters: [
{ {
name: 'All Files', name: 'All Files',
extensions: [ext], extensions: ['json'],
}, },
], ],
}) })
if (path) { if (path) {
await copyFile(srcLogFile, path) const logs = await logger.queryAllLogs()
const json = JSON.stringify(logs)
await writeToFile(path, json)
} }
} }

12
src/helpers/pname.js

@ -0,0 +1,12 @@
// @flow
// Infer a "pname" aka short id version of process name
const pname =
typeof window === 'undefined'
? process.env.IS_INTERNAL_PROCESS
? 'internal'
: 'main'
: 'renderer'
export default pname

16
src/helpers/resolveLogsDirectory.js

@ -1,6 +1,5 @@
// @flow // @flow
import fs from 'fs'
import path from 'path' import path from 'path'
const resolveLogsDirectory = () => { const resolveLogsDirectory = () => {
@ -11,18 +10,3 @@ const resolveLogsDirectory = () => {
} }
export default resolveLogsDirectory export default resolveLogsDirectory
export const getCurrentLogFile = () =>
new Promise((resolve, reject) => {
const dir = resolveLogsDirectory()
fs.readdir(dir, (err, files) => {
if (err) {
reject(err)
} else {
// last file is always the most up to date log. file will rotate.
const last = files[files.length - 1]
if (!last) reject(new Error('no logs'))
else resolve(path.resolve(dir, last))
}
})
})

2
src/internals/index.js

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

1
src/logger/logger-storybook.js

@ -1,7 +1,6 @@
const noop = () => {} const noop = () => {}
module.exports = { module.exports = {
setProcessShortName: noop,
onCmd: noop, onCmd: noop,
onDB: noop, onDB: noop,
onReduxAction: noop, onReduxAction: noop,

56
src/logger/logger.js

@ -4,6 +4,7 @@ import winston from 'winston'
import Transport from 'winston-transport' import Transport from 'winston-transport'
import resolveLogsDirectory from 'helpers/resolveLogsDirectory' import resolveLogsDirectory from 'helpers/resolveLogsDirectory'
import anonymizer from 'helpers/anonymizer' import anonymizer from 'helpers/anonymizer'
import pname from 'helpers/pname'
import { import {
DEBUG_DEVICE, DEBUG_DEVICE,
@ -19,8 +20,6 @@ import {
require('winston-daily-rotate-file') require('winston-daily-rotate-file')
let pname = '?'
const { format } = winston const { format } = winston
const { combine, json, timestamp } = format const { combine, json, timestamp } = format
@ -29,16 +28,49 @@ const pinfo = format(info => {
return info return info
}) })
const transports = [ function createDailyRotateFile(processName) {
new winston.transports.DailyRotateFile({ return new winston.transports.DailyRotateFile({
dirname: resolveLogsDirectory(), dirname: resolveLogsDirectory(),
json: true,
zippedArchive: true, zippedArchive: true,
filename: 'application-%DATE%.log', filename: `ledger-live-${processName}-%DATE%.log`,
datePattern: 'YYYY-MM-DD', datePattern: 'YYYY-MM-DD',
maxSize: '20m', maxSize: '10m',
maxFiles: '14d', maxFiles: '14d',
}), })
] }
const transports = [createDailyRotateFile(pname)]
const queryLogs = (processName: string) =>
new Promise((resolve, reject) => {
const dailyRotateFile = createDailyRotateFile(processName)
const options = {
from: new Date() - 60 * 60 * 1000,
until: new Date(),
limit: 100,
start: 0,
order: 'desc',
}
dailyRotateFile.query(options, (err, result) => {
if (err) {
reject(err)
return
}
resolve(result)
})
})
const queryAllLogs = async () => {
const internal = await queryLogs('internal')
const main = await queryLogs('main')
const renderer = await queryLogs('renderer')
const all = internal
.concat(main)
.concat(renderer)
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
return all
}
if (process.env.NODE_ENV !== 'production' || process.env.DEV_TOOLS) { if (process.env.NODE_ENV !== 'production' || process.env.DEV_TOOLS) {
let consoleT let consoleT
@ -125,12 +157,6 @@ const blacklistTooVerboseCommandResponse = [
] ]
export default { export default {
setProcessShortName: (processShortName: string) => {
pname = processShortName
},
getProcessShortName: () => pname,
onCmd: (type: string, id: string, spentTime: number, data?: any) => { onCmd: (type: string, id: string, spentTime: number, data?: any) => {
if (logCmds) { if (logCmds) {
switch (type) { switch (type) {
@ -352,4 +378,6 @@ export default {
} }
} }
}, },
queryAllLogs,
} }

3
src/main/bridge.js

@ -17,8 +17,6 @@ import { setInternalProcessPID } from './terminator'
import { getMainWindow } from './app' import { getMainWindow } from './app'
logger.setProcessShortName('main')
// sqlite files will be located in the app local data folder // sqlite files will be located in the app local data folder
const LEDGER_LIVE_SQLITE_PATH = path.resolve(app.getPath('userData'), 'sqlite') const LEDGER_LIVE_SQLITE_PATH = path.resolve(app.getPath('userData'), 'sqlite')
const LEDGER_LOGS_DIRECTORY = process.env.LEDGER_LOGS_DIRECTORY || resolveLogsDirectory() const LEDGER_LOGS_DIRECTORY = process.env.LEDGER_LOGS_DIRECTORY || resolveLogsDirectory()
@ -51,6 +49,7 @@ const bootInternalProcess = () => {
internalProcess = fork(forkBundlePath, { internalProcess = fork(forkBundlePath, {
env: { env: {
...process.env, ...process.env,
IS_INTERNAL_PROCESS: 1,
LEDGER_LOGS_DIRECTORY, LEDGER_LOGS_DIRECTORY,
LEDGER_CONFIG_DIRECTORY, LEDGER_CONFIG_DIRECTORY,
LEDGER_LIVE_SQLITE_PATH, LEDGER_LIVE_SQLITE_PATH,

2
src/renderer/init.js

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

4
src/sentry/install.js

@ -1,5 +1,5 @@
// @flow // @flow
import logger from 'logger' import pname from 'helpers/pname'
import anonymizer from 'helpers/anonymizer' import anonymizer from 'helpers/anonymizer'
/* eslint-disable no-continue */ /* eslint-disable no-continue */
@ -24,7 +24,7 @@ export default (Raven: any, shouldSendCallback: () => boolean, userId: string) =
sentry: true, sentry: true,
}, },
extra: { extra: {
process: logger.getProcessShortName(), process: pname,
}, },
dataCallback: (data: mixed) => { dataCallback: (data: mixed) => {
// We are mutating the data to anonymize everything. // We are mutating the data to anonymize everything.

Loading…
Cancel
Save