Closes #296. Add logging to `Help Debug Editor` command

This commit is contained in:
Glavin Wiechert 2015-05-04 02:12:02 -03:00
parent 88c58a20bb
commit 1dfac5bbab
5 changed files with 124 additions and 87 deletions

View File

@ -48,7 +48,7 @@
"atom": ">0.50.0"
},
"dependencies": {
"analytics-node": "^1.0.2",
"analytics-node": "^1.2.2",
"async": "^0.9.0",
"atom-message-panel": "^1.1.1",
"atom-space-pen-views": "^2.0.3",
@ -59,6 +59,7 @@
"diff": "^1.3.2",
"editorconfig": "^0.11.4",
"emissary": "^1.0.0",
"event-kit": "^1.1.0",
"expand-home-dir": "0.0.2",
"extend": "^1.2.1",
"js-beautify": "^1.5.5",

View File

@ -180,10 +180,6 @@ module.exports = class Beautifier
)
)
###
Methods to copy over from Winston's Logger
###
_loggerMethods: ['silly','debug','verbose','info','warn','error']
###
Logger instance
###
@ -192,34 +188,12 @@ module.exports = class Beautifier
Initialize and configure Logger
###
setupLogger: ->
winston = require('winston')
# Create Transport with Writable Stream
# See http://stackoverflow.com/a/21583831/2578205
stream = require('stream')
writable = new stream.Writable({
write: (chunk, encoding, next) ->
console.log(chunk.toString())
next()
})
transport = new (winston.transports.File)({
name: @name
level: 'warn'
timestamp: true
prettyPrint: true
colorize: true
stream: writable
json: false
})
# Initialize logger
@logger = new (winston.Logger)({
# Configure transports
transports: [
transport
]
})
@logger = require('../logger')(__filename)
# console.log(@logger)
# Merge logger methods into beautifier class
for method in @_loggerMethods
@[method] = @logger[method]
for key, method of @logger
# console.log(key, method)
@[key] = method
@verbose("Beautifier logger has been initialized.")
###

View File

@ -3,6 +3,7 @@ _plus = require('underscore-plus')
Promise = require('bluebird')
Languages = require('../languages/')
path = require('path')
logger = require('../logger')(__filename)
# Lazy loaded dependencies
extend = null
@ -119,12 +120,12 @@ module.exports = class Beautifiers
if options is true
# Beautifier supports all options for this language
if laOp
# console.log('add supported beautifier', languageName, beautifierName)
# logger.verbose('add supported beautifier', languageName, beautifierName)
for field, op of laOp
op.beautifiers.push(beautifierName)
else
# Supports language but no options specifically
console.warn("Could not find options for language: #{languageName}")
logger.warn("Could not find options for language: #{languageName}")
else if typeof options is "object"
# Iterate over beautifier's options for this language
for field, op of options
@ -135,7 +136,7 @@ module.exports = class Beautifiers
laOp?[field]?.beautifiers.push(beautifierName)
else if typeof op is "string"
# Rename
# console.log('support option with rename:', field, op, languageName, beautifierName, langOptions)
# logger.verbose('support option with rename:', field, op, languageName, beautifierName, langOptions)
languages[languageName]?.beautifiers.push(beautifierName)
laOp?[op]?.beautifiers.push(beautifierName)
else if typeof op is "function"
@ -152,7 +153,7 @@ module.exports = class Beautifiers
laOp?[f]?.beautifiers.push(beautifierName)
else
# Unsupported
console.warn("Unsupported option:", beautifierName, languageName, field, op, langOptions)
logger.warn("Unsupported option:", beautifierName, languageName, field, op, langOptions)
# Prefix language's options with namespace
for langName, ops of langOptions
@ -160,7 +161,7 @@ module.exports = class Beautifiers
lang = languages[langName]
# Use the namespace from language as key prefix
prefix = lang.namespace
# console.log(langName, lang, prefix, ops)
# logger.verbose(langName, lang, prefix, ops)
# Iterate over all language options and rename fields
for field, op of ops
# Rename field
@ -169,15 +170,15 @@ module.exports = class Beautifiers
# Flatten Options per language to array of all options
allOptions = _.values(langOptions)
# console.log('allOptions', allOptions)
# logger.verbose('allOptions', allOptions)
# Flatten array of objects to single object for options
flatOptions = _.reduce(allOptions, ((result, languageOptions, language) ->
# Iterate over fields (keys) in Language's Options
# and merge them into single result
# console.log('language options', language, languageOptions, result)
# logger.verbose('language options', language, languageOptions, result)
return _.reduce(languageOptions, ((result, optionDef, optionName) ->
# TODO: Add supported beautifiers to option description
# console.log('optionDef', optionDef, optionName)
# logger.verbose('optionDef', optionDef, optionName)
if optionDef.beautifiers.length > 0
# optionDef.title = "#{optionDef.title} - Supported by #{optionDef.beautifiers.join(', ')}"
optionDef.description = "#{optionDef.description} (Supported by #{optionDef.beautifiers.join(', ')})"
@ -185,16 +186,16 @@ module.exports = class Beautifiers
# optionDef.title = "(DEPRECATED) #{optionDef.title}"
optionDef.description = "#{optionDef.description} (Not supported by any beautifiers)"
if result[optionName]?
console.warn("Duplicate option detected: ", optionName, optionDef)
logger.warn("Duplicate option detected: ", optionName, optionDef)
result[optionName] = optionDef
return result
), result)
), {})
# Generate Language configurations
# console.log('languages', languages)
# logger.verbose('languages', languages)
for langName, lang of languages
# console.log(langName, lang)
# logger.verbose(langName, lang)
name = lang.name
beautifiers = lang.beautifiers
optionName = "language_#{lang.namespace}"
@ -212,21 +213,22 @@ module.exports = class Beautifiers
description: "Default Beautifier to be used for #{name}"
enum: _.uniq(beautifiers)
}
# console.log('flatOptions', flatOptions)
# logger.verbose('flatOptions', flatOptions)
return flatOptions
###
###
getBeautifiers: (language, options) ->
# console.log(@beautifiers)
# logger.verbose(@beautifiers)
_.filter(@beautifiers, (beautifier) ->
# console.log('beautifier',beautifier, language)
# logger.verbose('beautifier',beautifier, language)
_.contains(beautifier.languages, language)
)
beautify: (text, allOptions, grammar, filePath) ->
return new Promise((resolve, reject) =>
logger.info('beautify', text, allOptions, grammar, filePath)
# Get language
fileExtension = path.extname(filePath)
@ -258,9 +260,9 @@ module.exports = class Beautifiers
options = _.merge(@getOptions(fallback, allOptions) || {}, options)
# Get Beautifier
# console.log(grammar, language)
logger.verbose(grammar, language)
beautifiers = @getBeautifiers(language.name, options)
# console.log('beautifiers', beautifiers)
# logger.verbose('beautifiers', beautifiers)
# Check if unsupported language
if beautifiers.length < 1
@ -270,7 +272,7 @@ module.exports = class Beautifiers
beautifier = _.find(beautifiers, (beautifier) ->
beautifier.name is preferredBeautifierName
) or beautifiers[0]
# console.log('beautifier', beautifier.name, beautifiers)
logger.verbose('beautifier', beautifier.name, beautifiers)
transformOptions = (beautifier, languageName, options) ->
# Transform options, if applicable
@ -308,7 +310,7 @@ module.exports = class Beautifiers
# Replace old options with new transformed options
return transformedOptions
else
console.warn("Unsupported Language options: ", beautifierOptions)
logger.warn("Unsupported Language options: ", beautifierOptions)
return options
# Apply language-specific option transformations
@ -416,22 +418,22 @@ module.exports = class Beautifiers
getConfigOptionsFromSettings: (langs) ->
config = atom.config.get('atom-beautify')
options = {}
# console.log(langs, config);
# logger.verbose(langs, config);
# Iterate over keys of the settings
_.every _.keys(config), (k) ->
# Check if keys start with a language
p = k.split("_")[0]
idx = _.indexOf(langs, p)
# console.log(k, p, idx);
# logger.verbose(k, p, idx);
if idx >= 0
# Remove the language prefix and nest in options
lang = langs[idx]
opt = k.replace(new RegExp("^" + lang + "_"), "")
options[lang] = options[lang] or {}
options[lang][opt] = config[k]
# console.log(lang, opt);
# logger.verbose(lang, opt);
true
# console.log(options);
# logger.verbose(options);
options
@ -455,13 +457,13 @@ module.exports = class Beautifiers
strip ?= require("strip-json-comments")
externalOptions = JSON.parse(strip(contents))
catch e
# console.log "Failed parsing config as JSON: " + configPath
# logger.verbose "Failed parsing config as JSON: " + configPath
# Attempt as YAML
try
yaml ?= require("yaml-front-matter")
externalOptions = yaml.safeLoad(contents)
catch e
console.log "Failed parsing config as YAML and JSON: " + configPath
logger.verbose "Failed parsing config as YAML and JSON: " + configPath
externalOptions = {}
else
externalOptions = {}
@ -518,7 +520,7 @@ module.exports = class Beautifiers
pc = @getConfig(pf, false)
# Add config for p to project's config options
projectOptions.push(pc)
# console.log p, pc
# logger.verbose p, pc
# Move upwards
p = path.resolve(p,"../")
else
@ -533,14 +535,14 @@ module.exports = class Beautifiers
editorConfigOptions
]
allOptions = allOptions.concat(projectOptions)
# console.log(allOptions)
# logger.verbose(allOptions)
return allOptions
getOptions: (selection, allOptions) ->
self = this
_ ?= require("lodash")
extend ?= require("extend")
# console.log(selection, allOptions);
# logger.verbose(selection, allOptions);
# Reduce all options into correctly merged options.
options = _.reduce(allOptions, (result, currOptions) ->
containsNested = false
@ -552,21 +554,21 @@ module.exports = class Beautifiers
if _.indexOf(self.languages.namespaces, key) >= 0 and typeof currOptions[key] is "object" # Check if nested object (more options in value)
containsNested = true
break # Found, break out of loop, no need to continue
# console.log(containsNested, currOptions);
# logger.verbose(containsNested, currOptions);
# Create a flat object of config options if nested format was used
unless containsNested
_.merge collectedConfig, currOptions
else
# Merge with selected options
# where `selection` could be `html`, `js`, 'css', etc
# console.log(selection, currOptions[selection]);
# logger.verbose(selection, currOptions[selection]);
_.merge collectedConfig, currOptions[selection]
extend result, collectedConfig
, {} )
# TODO: Clean.
# There is a bug in nopt
# See https://github.com/npm/nopt/issues/38#issuecomment-45971505
# console.log('pre-clean', JSON.stringify(options));
# logger.verbose('pre-clean', JSON.stringify(options));
#options = cleanOptions(options, knownOpts);
#console.log('post-clean', JSON.stringify(options));
#logger.verbose('post-clean', JSON.stringify(options));
options

View File

@ -16,10 +16,7 @@ yaml = null
async = null
dir = null # Node-Dir
LoadingView = null
MessagePanelView = null
PlainMessageView = null
$ = null
#MessageView = require "./views/message-view"
# function cleanOptions(data, types) {
# nopt.clean(data, types);
@ -47,23 +44,19 @@ setCursors = (editor, posArray) ->
beautify = ({onSave}) ->
path ?= require("path")
MessagePanelView ?= require('atom-message-panel').MessagePanelView
PlainMessageView ?= require('atom-message-panel').PlainMessageView
LoadingView ?= require "./views/loading-view"
@messagePanel ?= new MessagePanelView title: 'Atom Beautify Error Messages'
@loadingView ?= new LoadingView()
@loadingView.show()
forceEntireFile = onSave && atom.config.get("atom-beautify.beautifyEntireFileOnSave")
# Show error
showError = (e) =>
showError = (error) =>
@loadingView.hide()
if not atom.config.get("atom-beautify.muteAllErrors")
# console.log(e)
@messagePanel.attach()
@messagePanel.add(new PlainMessageView({
message: e.message,
className: 'text-error'
}))
stack = error.stack
detail = error.message
atom.notifications?.addFatalError(error.message, {
stack, detail, dismissable: true })
# Get the path to the config file
# All of the options
@ -264,10 +257,11 @@ debug = () ->
# Grammar
addInfo('Original File Grammar', grammarName)
# Contents
# Get current editor's text
text = editor.getText()
addInfo('Original File Contents', "\n```#{grammarName}\n#{text}\n```")
# Contents
codeBlockSyntax = grammarName.toLowerCase().split(' ')[0]
addInfo('Original File Contents', "\n```#{codeBlockSyntax}\n#{text}\n```")
addHeader(2, "Beautification options")
@ -298,11 +292,20 @@ debug = () ->
"Options from `.jsbeautifyrc` files starting from directory `#{path.dirname(filePath)}` and going up to root\n" +
"```json\n#{JSON.stringify(projectOptions, undefined, 4)}\n```")
logs = ""
logger = require('./logger')(__filename)
subscription = logger.onLogging((msg) ->
# console.log('logging', msg)
logs += msg
)
addHeader(2, "Logs")
cb = (result) ->
subscription.dispose()
# Error logs
addInfo('Error logs', '*Not yet supported*')
addHeader(2, "Results")
# Logs
addInfo('Beautified File Contents', "\n```#{codeBlockSyntax}\n#{result}\n```")
addInfo('Logs', "\n```\n#{logs}\n```")
# Save to clipboard
atom.clipboard.write(debugInfo)
@ -313,6 +316,14 @@ debug = () ->
'Warning: Be sure to look over the debug info before you send it,
to ensure you are not sharing undesirable private information.')
try
beautifier.beautify(text, allOptions, grammarName, filePath)
.then(cb)
.catch(cb)
catch e
return cb(e)
handleSaveEvent = =>
atom.workspace.observeTextEditors (editor) =>
buffer = editor.getBuffer()

49
src/logger.coffee Normal file
View File

@ -0,0 +1,49 @@
###
Global Logger
###
module.exports = do ->
# Create Event Emitter
{Emitter} = require 'event-kit'
emitter = new Emitter()
# Create Transport with Writable Stream
# See http://stackoverflow.com/a/21583831/2578205
winston = require('winston')
stream = require('stream')
writable = new stream.Writable({
write: (chunk, encoding, next) ->
msg = chunk.toString()
# console.log msg
emitter.emit('logging', msg)
next()
})
return (label) ->
transport = new (winston.transports.File)({
label: label
level: 'debug'
timestamp: true
# prettyPrint: true
# colorize: true
stream: writable
json: false
})
# Initialize logger
wlogger = new (winston.Logger)({
# Configure transports
transports: [
transport
]
})
# Export logger methods
loggerMethods = ['silly','debug','verbose','info','warn','error']
logger = {}
for method in loggerMethods
logger[method] = wlogger[method]
# Add logger listener
logger.onLogging = (handler) ->
# console.log('onLogging', handler)
subscription = emitter.on('logging', handler)
# console.log('emitter', emitter.handlersByEventName, subscription)
return subscription
# Return simplified logger
return logger