Merge branch 'new-log'

This commit is contained in:
David Capello 2016-02-26 17:11:51 -03:00
commit bc9c3b0ec2
9 changed files with 199 additions and 65 deletions

View File

@ -109,8 +109,8 @@ public:
// This is a raw pointer because we want to delete this explicitly. // This is a raw pointer because we want to delete this explicitly.
app::crash::DataRecovery* m_recovery; app::crash::DataRecovery* m_recovery;
Modules(bool verbose) Modules(bool createLogInDesktop)
: m_loggerModule(verbose) : m_loggerModule(createLogInDesktop)
, m_recovery(nullptr) { , m_recovery(nullptr) {
} }
@ -164,10 +164,23 @@ void App::initialize(const AppOptions& options)
if (m_isGui) if (m_isGui)
m_uiSystem.reset(new ui::UISystem); m_uiSystem.reset(new ui::UISystem);
// Initializes the application loading the modules, setting the
// graphics mode, loading the configuration and resources, etc.
m_coreModules = new CoreModules; m_coreModules = new CoreModules;
m_modules = new Modules(options.verbose());
bool createLogInDesktop = false;
switch (options.verboseLevel()) {
case AppOptions::kNoVerbose:
base::set_log_level(ERROR);
break;
case AppOptions::kVerbose:
base::set_log_level(INFO);
break;
case AppOptions::kHighlyVerbose:
base::set_log_level(VERBOSE);
createLogInDesktop = true;
break;
}
m_modules = new Modules(createLogInDesktop);
m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0); m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0);
m_brushes.reset(new AppBrushes); m_brushes.reset(new AppBrushes);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -24,7 +24,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
: m_exeName(base::get_file_name(argv[0])) : m_exeName(base::get_file_name(argv[0]))
, m_startUI(true) , m_startUI(true)
, m_startShell(false) , m_startShell(false)
, m_verboseEnabled(false) , m_verboseLevel(kNoVerbose)
, m_palette(m_po.add("palette").requiresValue("<filename>").description("Use a specific palette by default")) , m_palette(m_po.add("palette").requiresValue("<filename>").description("Use a specific palette by default"))
, m_shell(m_po.add("shell").description("Start an interactive console to execute scripts")) , m_shell(m_po.add("shell").description("Start an interactive console to execute scripts"))
, m_batch(m_po.add("batch").mnemonic('b').description("Do not start the UI")) , m_batch(m_po.add("batch").mnemonic('b').description("Do not start the UI"))
@ -52,13 +52,18 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_listLayers(m_po.add("list-layers").description("List layers of the next given sprite\nor include layers in JSON data")) , m_listLayers(m_po.add("list-layers").description("List layers of the next given sprite\nor include layers in JSON data"))
, m_listTags(m_po.add("list-tags").description("List tags of the next given sprite sprite\nor include frame tags in JSON data")) , m_listTags(m_po.add("list-tags").description("List tags of the next given sprite sprite\nor include frame tags in JSON data"))
, m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done")) , m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done"))
, m_debug(m_po.add("debug").description("Extreme verbose mode and\ncopy log to desktop"))
, m_help(m_po.add("help").mnemonic('?').description("Display this help and exits")) , m_help(m_po.add("help").mnemonic('?').description("Display this help and exits"))
, m_version(m_po.add("version").description("Output version information and exit")) , m_version(m_po.add("version").description("Output version information and exit"))
{ {
try { try {
m_po.parse(argc, argv); m_po.parse(argc, argv);
m_verboseEnabled = m_po.enabled(m_verbose); if (m_po.enabled(m_debug))
m_verboseLevel = kHighlyVerbose;
else if (m_po.enabled(m_verbose))
m_verboseLevel = kVerbose;
m_paletteFileName = m_po.value_of(m_palette); m_paletteFileName = m_po.value_of(m_palette);
m_startShell = m_po.enabled(m_shell); m_startShell = m_po.enabled(m_shell);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -19,6 +19,12 @@ namespace app {
class AppOptions { class AppOptions {
public: public:
enum VerboseLevel {
kNoVerbose,
kVerbose,
kHighlyVerbose,
};
typedef base::ProgramOptions PO; typedef base::ProgramOptions PO;
typedef PO::Option Option; typedef PO::Option Option;
typedef PO::ValueList ValueList; typedef PO::ValueList ValueList;
@ -27,7 +33,7 @@ public:
bool startUI() const { return m_startUI; } bool startUI() const { return m_startUI; }
bool startShell() const { return m_startShell; } bool startShell() const { return m_startShell; }
bool verbose() const { return m_verboseEnabled; } VerboseLevel verboseLevel() const { return m_verboseLevel; }
const std::string& paletteFileName() const { return m_paletteFileName; } const std::string& paletteFileName() const { return m_paletteFileName; }
@ -70,7 +76,7 @@ private:
base::ProgramOptions m_po; base::ProgramOptions m_po;
bool m_startUI; bool m_startUI;
bool m_startShell; bool m_startShell;
bool m_verboseEnabled; VerboseLevel m_verboseLevel;
std::string m_paletteFileName; std::string m_paletteFileName;
Option& m_palette; Option& m_palette;
@ -101,6 +107,7 @@ private:
Option& m_listTags; Option& m_listTags;
Option& m_verbose; Option& m_verbose;
Option& m_debug;
Option& m_help; Option& m_help;
Option& m_version; Option& m_version;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -17,19 +17,17 @@
namespace app { namespace app {
static LoggerModule* logger_instance = NULL; LoggerModule::LoggerModule(bool createLogInDesktop)
LoggerModule::LoggerModule(bool verbose)
: m_verbose(verbose)
{ {
logger_instance = this; app::ResourceFinder rf(false);
if (verbose) { if (createLogInDesktop)
app::ResourceFinder rf(false); rf.includeDesktopDir(PACKAGE "-v" VERSION "-DebugOutput.txt");
else
rf.includeUserDir("aseprite.log"); rf.includeUserDir("aseprite.log");
auto filename = rf.defaultFilename();
base_set_log_filename(filename.c_str()); auto filename = rf.defaultFilename();
} base::set_log_filename(filename.c_str());
} }
LoggerModule::~LoggerModule() LoggerModule::~LoggerModule()
@ -37,8 +35,7 @@ LoggerModule::~LoggerModule()
LOG("Logger module: shutting down (this is the last line)\n"); LOG("Logger module: shutting down (this is the last line)\n");
// Close log file // Close log file
base_set_log_filename(""); base::set_log_filename("");
logger_instance = nullptr;
} }
} // namespace app } // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -13,13 +13,8 @@ namespace app {
class LoggerModule { class LoggerModule {
public: public:
LoggerModule(bool verbose); LoggerModule(bool createLogInDesktop);
~LoggerModule(); ~LoggerModule();
bool isVerbose() const { return m_verbose; }
private:
bool m_verbose;
}; };
} // namespace app } // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -19,6 +19,11 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#endif
namespace app { namespace app {
ResourceFinder::ResourceFinder(bool log) ResourceFinder::ResourceFinder(bool log)
@ -163,6 +168,41 @@ void ResourceFinder::includeUserDir(const char* filename)
#endif #endif
} }
void ResourceFinder::includeDesktopDir(const char* filename)
{
#ifdef _WIN32
std::vector<wchar_t> buf(MAX_PATH);
HRESULT hr = SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
SHGFP_TYPE_DEFAULT, &buf[0]);
if (hr == S_OK) {
addPath(base::join_path(base::to_utf8(&buf[0]), filename));
}
else {
includeHomeDir(filename);
}
#elif defined(__APPLE__)
// TODO get the desktop folder
// $HOME/Desktop/filename
includeHomeDir(base::join_path(std::string("Desktop"), filename).c_str());
#else
char* desktopDir = std::getenv("XDG_DESKTOP_DIR");
if (desktopDir) {
// $XDG_DESKTOP_DIR/filename
addPath(base::join_path(desktopDir, filename));
}
else {
// $HOME/Desktop/filename
includeHomeDir(base::join_path(std::string("Desktop"), filename).c_str());
}
#endif
}
std::string ResourceFinder::getFirstOrCreateDefault() std::string ResourceFinder::getFirstOrCreateDefault()
{ {
std::string fn; std::string fn;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -51,6 +51,8 @@ namespace app {
// - The filename will be in $HOME/.config/aseprite/ // - The filename will be in $HOME/.config/aseprite/
void includeUserDir(const char* filename); void includeUserDir(const char* filename);
void includeDesktopDir(const char* filename);
// Returns the first file found or creates the whole directory // Returns the first file found or creates the whole directory
// structure to create the file in its default location. // structure to create the file in its default location.
std::string getFirstOrCreateDefault(); std::string getFirstOrCreateDefault();

View File

@ -1,5 +1,5 @@
// Aseprite Base Library // Aseprite Base Library
// Copyright (c) 2001-2015 David Capello // Copyright (c) 2001-2016 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -10,47 +10,99 @@
#include "base/log.h" #include "base/log.h"
#include "base/file_handle.h" #include "base/fstream_path.h"
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <fstream>
#include <iostream>
#include <string> #include <string>
static FILE* log_fileptr = nullptr; namespace {
static std::string log_filename;
void base_set_log_filename(const char* filename) class nullbuf : public std::streambuf {
{ protected:
if (log_fileptr) { int_type overflow(int_type ch) override {
fclose(log_fileptr); return traits_type::not_eof(ch);
log_fileptr = nullptr;
} }
};
class nullstream : public std::ostream {
public:
nullstream()
: std::basic_ios<char_type, traits_type>(&m_buf)
, std::ostream(&m_buf) { }
private:
nullbuf m_buf;
};
LogLevel log_level = LogLevel::NONE;
nullstream null_stream;
std::ofstream log_stream;
std::string log_filename;
bool open_log_stream()
{
if (!log_stream.is_open()) {
if (log_filename.empty())
return false;
log_stream.open(FSTREAM_PATH(log_filename));
}
return log_stream.is_open();
}
void log_text(const char* text)
{
if (!open_log_stream())
return;
log_stream.write(text, strlen(text));
log_stream.flush();
}
} // anonymous namespace
void base::set_log_filename(const char* filename)
{
if (log_stream.is_open())
log_stream.close();
log_filename = filename; log_filename = filename;
} }
void base_log(const char* format, ...) void base::set_log_level(LogLevel level)
{ {
if (!log_fileptr) { log_level = level;
if (log_filename.empty()) }
return;
log_fileptr = base::open_file_raw(log_filename, "w"); std::ostream& base::get_log_stream(LogLevel level)
} {
ASSERT(level != NONE);
if (log_fileptr) { if ((log_level < level) ||
va_list ap; (!log_stream.is_open() && !open_log_stream()))
va_start(ap, format); return null_stream;
else
return log_stream;
}
vfprintf(log_fileptr, format, ap); void LOG(const char* format, ...)
fflush(log_fileptr); {
if (log_level < INFO)
return;
char buf[2048];
va_list ap;
va_start(ap, format);
std::vsnprintf(buf, sizeof(buf)-1, format, ap);
log_text(buf);
#ifdef _DEBUG #ifdef _DEBUG
va_start(ap, format); fputs(buf, stderr);
vfprintf(stderr, format, ap); fflush(stderr);
fflush(stderr);
#endif #endif
va_end(ap); va_end(ap);
}
} }

View File

@ -1,5 +1,5 @@
// Aseprite Base Library // Aseprite Base Library
// Copyright (c) 2001-2015 David Capello // Copyright (c) 2001-2016 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -8,12 +8,35 @@
#define BASE_LOG_H_INCLUDED #define BASE_LOG_H_INCLUDED
#pragma once #pragma once
// Define BASE_DONT_DEFINE_LOG_MACRO in case that you don't need LOG enum LogLevel {
#ifndef BASE_DONT_DEFINE_LOG_MACRO NONE = 0, // Default log level: do not log
#define LOG base_log FATAL = 1, // Something failed and we CANNOT continue the execution
#endif ERROR = 2, // Something failed, the UI should show this, and we can continue
WARNING = 3, // Something failed, the UI don't need to show this, and we can continue
INFO = 4, // Information about some important event
VERBOSE = 5, // Information step by step
};
void base_set_log_filename(const char* filename); // E.g. LOG("text in information log level\n");
void base_log(const char* format, ...); void LOG(const char* format, ...);
#ifdef __cplusplus
#include <iosfwd>
namespace base {
void set_log_filename(const char* filename);
void set_log_level(LogLevel level);
std::ostream& get_log_stream(LogLevel level);
} // namespace base
// E.g. LOG(INFO) << "some information\n";
inline std::ostream& LOG(LogLevel level) {
return base::get_log_stream(level);
}
#endif
#endif #endif