Added log infrastructure. Only a few files of STK are actually using it,

but all (f)printfs should be replaced. Note that I had to rename
tinygettext/log.?pp to avoid linking problems on windows.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12351 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2013-01-14 00:38:07 +00:00
parent 996c563f9c
commit 5d8c0d7be1
13 changed files with 384 additions and 86 deletions

View File

@ -204,10 +204,10 @@ src/tinygettext/dictionary.cpp
src/tinygettext/dictionary_manager.cpp
src/tinygettext/iconv.cpp
src/tinygettext/language.cpp
src/tinygettext/log.cpp
src/tinygettext/plural_forms.cpp
src/tinygettext/po_parser.cpp
src/tinygettext/stk_file_system.cpp
src/tinygettext/tgt_log.cpp
src/tinygettext/tinygettext.cpp
src/tracks/ambient_light_sphere.cpp
src/tracks/bezier_curve.cpp
@ -233,6 +233,7 @@ src/tutorial/tutorial_data.cpp
src/tutorial/tutorial_manager.cpp
src/utils/constants.cpp
src/utils/leak_check.cpp
src/utils/log.cpp
src/utils/profiler.cpp
src/utils/random_generator.cpp
src/utils/string_utils.cpp
@ -464,11 +465,11 @@ src/tinygettext/dictionary_manager.hpp
src/tinygettext/file_system.hpp
src/tinygettext/iconv.hpp
src/tinygettext/language.hpp
src/tinygettext/log.hpp
src/tinygettext/log_stream.hpp
src/tinygettext/plural_forms.hpp
src/tinygettext/po_parser.hpp
src/tinygettext/stk_file_system.hpp
src/tinygettext/tgt_log.hpp
src/tinygettext/tinygettext.hpp
src/tracks/ambient_light_sphere.hpp
src/tracks/bezier_curve.hpp
@ -496,6 +497,7 @@ src/utils/aligned_array.hpp
src/utils/constants.hpp
src/utils/interpolation_array.hpp
src/utils/leak_check.hpp
src/utils/log.hpp
src/utils/no_copy.hpp
src/utils/profiler.hpp
src/utils/ptr_vector.hpp

View File

@ -27,6 +27,7 @@
#include "io/xml_node.hpp"
#include "items/item.hpp"
#include "karts/kart_properties.hpp"
#include "utils/log.hpp"
STKConfig* stk_config=0;
float STKConfig::UNDEFINED = -99.9f;
@ -79,9 +80,8 @@ void STKConfig::load(const std::string &filename)
catch(std::exception& err)
{
fprintf(stderr, "FATAL ERROR while reading StkConfig '%s':\n", filename.c_str());
fprintf(stderr, " %s", err.what());
fprintf(stderr, "\n");
Log::error("StkConfig", "FATAL ERROR while reading '%s':", filename.c_str());
Log::fatal("StkConfig", " %s", err.what());
exit(1);
}
delete root;
@ -89,25 +89,25 @@ void STKConfig::load(const std::string &filename)
// Check that all necessary values are indeed set
// -----------------------------------------------
#define CHECK_NEG( a,strA) if(a<=UNDEFINED) { \
fprintf(stderr,"Missing default value for '%s' in '%s'.\n", \
strA,filename.c_str());exit(-1); \
#define CHECK_NEG( a,strA) if(a<=UNDEFINED) { \
Log::fatal("StkConfig", "Missing default value for '%s' in '%s'.", \
strA,filename.c_str());exit(-1); \
}
if(m_score_increase.size()==0 || (int)m_score_increase.size()!=m_max_karts)
{
fprintf(stderr,"Not or not enough scores defined in stk_config");
Log::fatal("StkConfig", "Not or not enough scores defined in stk_config");
exit(-1);
}
if(m_leader_intervals.size()==0)
{
fprintf(stderr,"No follow leader interval(s) defined in stk_config");
Log::fatal("StkConfig", "No follow leader interval(s) defined in stk_config");
exit(-1);
}
if(m_switch_items.size()!=Item::ITEM_LAST-Item::ITEM_FIRST+1)
{
fprintf(stderr,"Wrong number of item switches defined in stk_config");
Log::fatal("StkConfig", "Wrong number of item switches defined in stk_config");
exit(-1);
}
@ -225,8 +225,8 @@ void STKConfig::getAllData(const XMLNode * root)
if(points<0 || from<0 || from>to||
(int)m_score_increase.size()!=from-1)
{
fprintf(stderr, "Incorrect GP point specification:\n");
fprintf(stderr, "from: %d to: %d points: %d\n",
Log::error("StkConfig", "Incorrect GP point specification:");
Log::fatal("StkConfig", "from: %d to: %d points: %d",
from, to, points);
exit(-1);
}
@ -272,8 +272,7 @@ void STKConfig::getAllData(const XMLNode * root)
m_title_music = MusicInformation::create(file_manager->getDataDir()
+ "/music/" + title_music );
if(!m_title_music)
fprintf(stderr, "Cannot load title music : %s\n",
title_music.c_str());
Log::error("StkConfig", "Cannot load title music : %s", title_music.c_str());
}
if(const XMLNode *history_node = root->getNode("history"))
@ -328,7 +327,7 @@ void STKConfig::getAllData(const XMLNode * root)
m_same_powerup_mode = POWERUP_MODE_ONLY_IF_SAME;
else
{
printf("Invalid item mode '%s' - ignored.\n",
Log::warn("StkConfig", "Invalid item mode '%s' - ignored.",
s.c_str());
}
}

View File

@ -640,6 +640,10 @@
RelativePath="..\..\utils\leak_check.cpp"
>
</File>
<File
RelativePath="..\..\utils\log.cpp"
>
</File>
<File
RelativePath="..\..\utils\profiler.cpp"
>
@ -1496,10 +1500,6 @@
RelativePath="..\..\tinygettext\language.cpp"
>
</File>
<File
RelativePath="..\..\tinygettext\log.cpp"
>
</File>
<File
RelativePath="..\..\tinygettext\plural_forms.cpp"
>
@ -1512,6 +1512,10 @@
RelativePath="..\..\tinygettext\stk_file_system.cpp"
>
</File>
<File
RelativePath="..\..\tinygettext\tgt_log.cpp"
>
</File>
<File
RelativePath="..\..\tinygettext\tinygettext.cpp"
>
@ -1778,6 +1782,10 @@
RelativePath="..\..\utils\leak_check.hpp"
>
</File>
<File
RelativePath="..\..\utils\log.hpp"
>
</File>
<File
RelativePath="..\..\utils\no_copy.hpp"
>
@ -2702,10 +2710,6 @@
RelativePath="..\..\tinygettext\language.hpp"
>
</File>
<File
RelativePath="..\..\tinygettext\log.hpp"
>
</File>
<File
RelativePath="..\..\tinygettext\log_stream.hpp"
>
@ -2722,6 +2726,10 @@
RelativePath="..\..\tinygettext\stk_file_system.hpp"
>
</File>
<File
RelativePath="..\..\tinygettext\tgt_log.hpp"
>
</File>
<File
RelativePath="..\..\tinygettext\tinygettext.hpp"
>

View File

@ -62,6 +62,7 @@
#include "graphics/material_manager.hpp"
#include "karts/kart_properties_manager.hpp"
#include "tracks/track_manager.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
@ -71,7 +72,7 @@
bool macSetBundlePathIfRelevant(std::string& data_dir)
{
printf("[FileManager] checking whether we are using an app bundle... ");
Log::debug("FileManager", "Checking whether we are using an app bundle... ");
// the following code will enable STK to find its data when placed in an
// app bundle on mac OS X.
// returns true if path is set, returns false if path was not set
@ -89,14 +90,14 @@ bool macSetBundlePathIfRelevant(std::string& data_dir)
std::string contents = std::string(path) + std::string("/Contents");
if(contents.find(".app") != std::string::npos)
{
printf("yes\n");
Log::debug("FileManager", "yes\n");
// executable is inside an app bundle, use app bundle-relative paths
data_dir = contents + std::string("/Resources/");
return true;
}
else
{
printf("no\n");
Log::debug("FileManager", "no\n");
return false;
}
}
@ -163,8 +164,8 @@ FileManager::FileManager(char *argv[])
#endif
// We can't use _() here, since translations will only be initalised
// after the filemanager (to get the path to the tranlsations from it)
fprintf(stderr, "[FileManager] Data files will be fetched from: '%s'\n",
m_root_dir.c_str() );
Log::info("FileManager", "Data files will be fetched from: '%s'",
m_root_dir.c_str());
checkAndCreateConfigDir();
checkAndCreateAddonsDir();
} // FileManager
@ -224,15 +225,15 @@ FileManager::~FileManager()
if(StringUtils::getExtension(*i)!="zip" &&
StringUtils::getExtension(*i)!="part" )
{
printf("[addons] Warning: unexpected tmp file '%s' found.\n",
full_path.c_str());
Log::warn("FileManager", "Unexpected tmp file '%s' found.",
full_path.c_str());
continue;
}
if(isDirectory(full_path))
{
// Gee, a .zip file which is a directory - stay away from it
printf("[addons] '%s' is a directory and will not be deleted.\n",
full_path.c_str());
Log::warn("FileManager", "'%s' is a directory and will not be deleted.",
full_path.c_str());
continue;
}
struct stat mystat;
@ -241,13 +242,13 @@ FileManager::~FileManager()
if(current - mystat.st_ctime <24*3600)
{
if(UserConfigParams::logAddons())
printf("[addons] '%s' is less than 24h old "
"and will not be deleted.\n",
full_path.c_str());
Log::verbose("FileManager", "'%s' is less than 24h old "
"and will not be deleted.",
full_path.c_str());
continue;
}
if(UserConfigParams::logAddons())
printf("[addons] Deleting tmp file'%s'.\n",full_path.c_str());
Log::verbose("FileManager", "Deleting tmp file'%s'.",full_path.c_str());
removeFile(full_path);
} // for i in all files in tmp
@ -282,7 +283,7 @@ XMLNode *FileManager::createXMLTree(const std::string &filename)
{
if (UserConfigParams::logMisc())
{
fprintf(stderr, "[FileManager::createXMLTree] %s\n", e.what());
Log::error("FileManager", "createXMLTree: %s\n", e.what());
}
return NULL;
}
@ -495,7 +496,7 @@ bool FileManager::checkAndCreateDirectory(const std::string &path)
if(m_file_system->existFile(io::path(path.c_str())))
return true;
std::cout << "[FileManager] Creating directory \"" << path << "\"\n";
Log::info("FileManager", "Creating directory '%s'.", path.c_str());
// Otherwise try to create the directory:
#if defined(WIN32) && !defined(__CYGWIN__)
@ -532,7 +533,7 @@ bool FileManager::checkAndCreateDirectoryP(const std::string &path)
{
if (!checkAndCreateDirectory(current_path))
{
fprintf(stderr, "[FileManager] Can't create dir '%s'",
Log::error("FileManager", "Can't create dir '%s'",
current_path.c_str());
break;
}
@ -557,7 +558,9 @@ void FileManager::checkAndCreateConfigDir()
}
else
{
#if defined(WIN32) || defined(__CYGWIN__)
// Try to use the APPDATA directory to store config files and highscore
// lists. If not defined, used the current directory.
if(getenv("APPDATA")!=NULL)
@ -576,7 +579,9 @@ void FileManager::checkAndCreateConfigDir()
m_config_dir += "/";
m_config_dir += CONFIGDIR;
#elif defined(__APPLE__)
if (getenv("HOME")!=NULL)
{
m_config_dir = getenv("HOME");
@ -592,7 +597,9 @@ void FileManager::checkAndCreateConfigDir()
m_config_dir += "/Library/Application Support/";
const std::string CONFIGDIR("SuperTuxKart");
m_config_dir += CONFIGDIR;
# else
#else
// Remaining unix variants. Use the new standards for config directory
// i.e. either XDG_CONFIG_HOME or $HOME/.config
if (getenv("XDG_CONFIG_HOME")!=NULL){
@ -619,16 +626,19 @@ void FileManager::checkAndCreateConfigDir()
}
}
m_config_dir += "/supertuxkart";
#endif
} // if(getenv("SUPERTUXKART_SAVEDIR") && checkAndCreateDirectory(...))
if(!checkAndCreateDirectory(m_config_dir))
{
std::cerr << "[FileManager] Can not create config dir '"
<< m_config_dir << "', falling back to '.'.\n";
Log::warn("FileManager", "Can not create config dir '%s', "
"falling back to '.'.", m_config_dir.c_str());
m_config_dir = ".";
}
Log::info("FileManager", "User directory is '%s'.", m_config_dir.c_str());
return;
} // checkAndCreateConfigDir
@ -655,15 +665,15 @@ void FileManager::checkAndCreateAddonsDir()
m_addons_dir = getenv("XDG_DATA_HOME");
dir_ok = checkAndCreateDirectory(m_addons_dir);
if(!dir_ok)
std::cerr << "[FileManager] Cannot create $XDG_DATA_HOME.\n";
Log::warn("FileManager", "Cannot create $XDG_DATA_HOME.");
// Do an additional test here, e.g. in case that XDG_DATA_HOME is '/'
// and since dir_ok is set, it would not test any of the other options
// like $HOME/.local/share
dir_ok = checkAndCreateDirectory(m_addons_dir+"/supertuxkart");
if(!dir_ok)
std::cerr
<< "[FileManager] Cannot create $XDG_DATA_HOME/supertuxkart.\n";
Log::warn("FileManager", "Cannot create "
"$XDG_DATA_HOME/supertuxkart.");
}
if(!dir_ok && getenv("HOME"))
@ -674,7 +684,7 @@ void FileManager::checkAndCreateAddonsDir()
// This tests for ".local" and then for ".local/share"
dir_ok = checkAndCreateDirectoryP(m_addons_dir);
if(!dir_ok)
std::cerr << "[FileManager] Cannot create $HOME/.local/share.\n";
Log::warn("FileManager", "Cannot create $HOME/.local/share.");
}
if(!dir_ok && getenv("HOME"))
{
@ -683,12 +693,12 @@ void FileManager::checkAndCreateAddonsDir()
m_addons_dir += "/.stkaddons";
dir_ok = checkAndCreateDirectory(m_addons_dir);
if(!dir_ok)
std::cerr << "[FileManager] Cannot create $HOME/.stkaddons.\n";
Log::warn("FileManager", "Cannot create $HOME/.stkaddons.");
}
if(!dir_ok)
{
std::cerr << "[FileManager] Falling back to use '.'.";
Log::warn("FileManager", "Falling back to use '.'.");
m_addons_dir = ".";
}
@ -697,8 +707,8 @@ void FileManager::checkAndCreateAddonsDir()
if(!dir_ok)
{
// If the directory can not be created, abort
std::cerr << " [FileManager] Cannot create directory '"
<< m_addons_dir<<"', falling back to use '.'.\n";
Log::error("FileManager", "Cannot create directory '%s', "
"falling back to use '.'.", m_addons_dir.c_str());
m_addons_dir=".";
}
@ -708,25 +718,22 @@ void FileManager::checkAndCreateAddonsDir()
if(!checkAndCreateDirectory(m_addons_dir))
{
fprintf(stderr,
"[FileManager] Can not create add-ons dir '%s', "
"falling back to '.'.\n", m_addons_dir.c_str());
Log::error("FileManager", "Can not create add-ons dir '%s', "
"falling back to '.'.", m_addons_dir.c_str());
m_addons_dir = ".";
}
std::cout << "[FileManager] Addons files will be stored in '"
<< m_addons_dir << "'.\n";
Log::info("FileManager", "Addons files will be stored in '%s'.",
m_addons_dir.c_str());
if (!checkAndCreateDirectory(m_addons_dir + "/icons/"))
{
fprintf(stderr,
"[FileManager] Failed to create add-ons icon dir at '%s'\n",
(m_addons_dir + "/icons/").c_str());
Log::error("FileManager", "Failed to create add-ons icon dir at '%s'.",
(m_addons_dir + "/icons/").c_str());
}
if (!checkAndCreateDirectory(m_addons_dir + "/tmp/"))
{
fprintf(stderr,
"[FileManager] Failed to create add-ons tmp dir at '%s'\n",
(m_addons_dir + "/tmp/").c_str());
Log::error("FileManager", "Failed to create add-ons tmp dir at '%s'.",
(m_addons_dir + "/tmp/").c_str());
}
} // checkAndCreateAddonsDir
@ -861,7 +868,6 @@ void FileManager::listFiles(std::set<std::string>& result,
#else
std::string path = is_full_path ? dir + "/" : m_root_dir+"/"+dir + "/";
#endif
//printf("******* Path : %s \n", path.c_str());
if(!isDirectory(path)) return;
@ -869,7 +875,7 @@ void FileManager::listFiles(std::set<std::string>& result,
if(!m_file_system->changeWorkingDirectoryTo( path.c_str() ))
{
printf("FileManager::listFiles : Could not change CWD!\n");
Log::error("FileManager", "listFiles : Could not change CWD!\n");
return;
}
irr::io::IFileList* files = m_file_system->createFileList();
@ -897,7 +903,7 @@ void FileManager::checkAndCreateDirForAddons(std::string addons_name,
bool success = checkAndCreateDirectory(path);
if(!success)
{
std::cout << "There is a problem with the addons dir." << std::endl;
Log::warn("FileManager", "There is a problem with the addons dir.");
return;
}
checkAndCreateDirectory(path+"/"+addons_name);
@ -931,7 +937,8 @@ bool FileManager::removeDirectory(const std::string &name) const
{
if((*i)=="." || (*i)=="..") continue;
if(UserConfigParams::logMisc())
printf("Deleting directory '%s'.\n", (*i).c_str());
Log::verbose("FileManager", "Deleting directory '%s'.",
(*i).c_str());
std::string full_path=name+"/"+*i;
if(isDirectory(full_path))
{

View File

@ -183,6 +183,7 @@
#include "tutorial/tutorial_manager.hpp"
#include "utils/constants.hpp"
#include "utils/leak_check.hpp"
#include "utils/log.hpp"
#include "utils/translation.hpp"
// ============================================================================
@ -431,6 +432,7 @@ void cmdLineHelp (char* invocation)
*/
int handleCmdLinePreliminary(int argc, char **argv)
{
int n;
for(int i=1; i<argc; i++)
{
if(argv[i][0] != '-') continue;
@ -476,7 +478,15 @@ int handleCmdLinePreliminary(int argc, char **argv)
{
UserConfigParams::m_log_errors=true;
}
else if( !strcmp(argv[i], "--log=nocolor"))
{
Log::disableColor();
printf("Colours disabled.\n");
}
else if(sscanf(argv[i], "--log=%d",&n)==1)
{
Log::setLogLevel(n);
}
else if ( !strcmp(argv[i], "--debug=all") )
{
UserConfigParams::m_verbosity |= UserConfigParams::LOG_ALL;
@ -1013,7 +1023,9 @@ int handleCmdLine(int argc, char **argv)
else if( !strcmp(argv[i], "--debug=misc" ) ) {}
else if( !strcmp(argv[i], "--debug=all" ) ) {}
else if( !strcmp(argv[i], "--log=terminal" ) ) {}
else if( !strcmp(argv[i], "--log=nocolor" ) ) {}
else if( !strcmp(argv[i], "--log=file" ) ) {}
else if( sscanf(argv[i], "--log=%d",&n )==1 ) {}
else if( !strcmp(argv[i], "--screensize") ||
!strcmp(argv[i], "-s") ) {i++;}
else if( !strcmp(argv[i], "--fullscreen") || !strcmp(argv[i], "-f")) {}

View File

@ -18,7 +18,7 @@
#ifndef HEADER_TINYGETTEXT_LOG_STREAM_HPP
#define HEADER_TINYGETTEXT_LOG_STREAM_HPP
#include "log.hpp"
#include "tgt_log.hpp"
namespace tinygettext {

View File

@ -16,7 +16,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <iostream>
#include "log.hpp"
#include "tgt_log.hpp"
namespace tinygettext {

View File

@ -18,6 +18,7 @@
#include "utils/leak_check.hpp"
#include "utils/log.hpp"
#include "utils/synchronised.hpp"
#include "utils/ptr_vector.hpp"
@ -107,19 +108,25 @@ namespace MemoryLeaks
* about those objects. */
void checkForLeaks()
{
std::cout << "checking for leaks... " << std::endl;
Log::verbose("LeackCheck", "checking for leaks... ");
Log::debug("LeackCheck", "checking for leaks... ");
Log::info("LeackCheck", "checking for leaks... ");
Log::warn("LeackCheck", "checking for leaks... ");
Log::error("LeackCheck", "checking for leaks... ");
Log::fatal("LeackCheck", "checking for leaks... ");
g_all_objects.lock();
if (g_all_objects.getData().size()>0)
{
std::cout << "leaks detected!!" << std::endl;
std::cout << "\n\n* * * * WARNING * * * * WARNING * * * * "
"MEMORY LEAK! * * * *\n" << std::endl;
std::cout << "LEAK CHECK: " << g_all_objects.getData().size()
<< " watched objects leaking" << std::endl;
Log::error("LeackCheck", "leaks detected!!");
Log::error("LeackCheck", "\n\n* * * * WARNING * * * * WARNING * * * * "
"MEMORY LEAK! * * * *");
Log::error("LeackCheck", "%d watched objects leaking.",
g_all_objects.getData().size());
}
else
{
std::cout << "ok (no watched class left leaking)" << std::endl;
Log::debug("LeackCheck", "ok (no watched class left leaking)");
}
std::set<AllocatedObject*>::iterator it;

View File

@ -22,6 +22,8 @@
#ifdef DEBUG
#include "utils/log.hpp"
#include <stdio.h>
namespace MemoryLeaks
@ -53,7 +55,7 @@ class LeakCheck : public MemoryLeaks::AllocatedObject\
{ public:\
virtual void print() const\
{ \
printf("Undeleted object at %s : %i\n", __FILE__, __LINE__);\
Log::error("LeakCheck", "Undeleted object at %s : %i\n", __FILE__, __LINE__); \
} \
virtual ~LeakCheck() {} \
}; \

164
src/utils/log.cpp Normal file
View File

@ -0,0 +1,164 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "utils/log.hpp"
#include "config/user_config.hpp"
#include <stdio.h>
#ifdef ANDROID
# include <android/log.h>
#endif
#ifdef WIN32
# include <windows.h>
#endif
Log::LogLevel Log::m_min_log_level = Log::LL_VERBOSE;
bool Log::m_no_colors = false;
// ----------------------------------------------------------------------------
/** Selects background/foreground colors for the message depending on
* log level. It is only called if messages are not redirected to a file.
* \param level The level for which to set the color.
*/
void Log::setTerminalColor(LogLevel level)
{
if(m_no_colors) return;
// Thanks to funto for the colouring code!
#ifdef WIN32
enum TermColor
{
TERM_BLACK, TERM_BLUE, TERM_GREEN, TERM_CYAN,
TERM_RED, TERM_MAGENTA, TERM_BROWN, TERM_LIGHTGRAY,
TERM_DARKGRAY, TERM_LIGHTBLUE, TERM_LIGHTGREEN, TERM_LIGHTCYAN,
TERM_LIGHTRED, TERM_LIGHTMAGENTA, TERM_YELLOW, TERM_WHITE
};
char color;
switch(level)
{
case LL_VERBOSE: color = TERM_BLACK << 4 | TERM_LIGHTGRAY; break;
case LL_DEBUG: color = TERM_BLACK << 4 | TERM_LIGHTGRAY; break;
case LL_INFO: color = TERM_BLACK << 4 | TERM_LIGHTGRAY; break;
case LL_WARN : color = TERM_LIGHTGRAY << 4 | TERM_LIGHTRED; break;
case LL_ERROR: color = TERM_LIGHTGRAY << 4 | TERM_RED; break;
case LL_FATAL: color = TERM_RED << 4 | TERM_WHITE; break;
} // switch
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
#elif defined(__APPLE__)
#else
enum TermAttr
{
TERM_RESET = 0, // "normal" mode
TERM_BRIGHT = 1,// more luminosity for the foreground
TERM_DIM = 2, // less luminosity for the foreground
};
enum TermColor
{
TERM_BLACK=0, TERM_RED, TERM_GREEN, TERM_YELLOW,
TERM_BLUE, TERM_MAGENTA, TERM_CYAN, TERM_WHITE
};
int attr = TERM_BRIGHT, front_color=-1;
switch(level)
{
case LL_VERBOSE: attr = TERM_DIM; front_color=TERM_WHITE; break;
case LL_DEBUG: attr = TERM_DIM; front_color=TERM_WHITE; break;
case LL_INFO: attr = TERM_RESET; break;
case LL_WARN: attr = TERM_DIM; front_color=TERM_RED; break;
case LL_ERROR: attr = TERM_BRIGHT; front_color=TERM_RED; break;
case LL_FATAL: attr = TERM_BRIGHT; front_color=TERM_RED; break;
}
if(attr==TERM_RESET)
printf("%c[%dm", 0x1B,attr); // not necessary, but
else
{
printf("%c[%d;%dm", 0x1B,attr, front_color+30);
}
#endif
} // setTerminalColor
// ----------------------------------------------------------------------------
/** Resets the terminal color to the default.
*/
void Log::resetTerminalColor()
{
if(m_no_colors)
{
printf("\n");
return;
}
#ifdef WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
/*TERM_BLACK*/0 << 4 | /*TERM_LIGHTGRAY*/7);
printf("\n");
#elif defined(__APPLE__)
printf("\n");
#else
printf("%c[0;;m\n", 0x1B);
#endif
} // resetTerminalColor
// ----------------------------------------------------------------------------
/** This actually prints the log message. If log messages are not redirected
* to a file, it tries to select a terminal colour.
* \param level Log level of the message to print.
* \param format A printf-like format string.
* \param va_list The values to be printed for the format.
*/
void Log::printMessage(int level, const char *component, const char *format,
VALIST va_list)
{
assert(level>=0 && level <=LL_FATAL);
if(level<m_min_log_level) return;
#ifdef ANDROID
android_LogPriority alp;
switch (level)
{
case LL_VERBOSE: alp = ANDROID_LOG_VERBOSE; break;
case LL_DEBUG: alp = ANDROID_LOG_DEBUG; break;
case LL_INFO: alp = ANDROID_LOG_INFO; break;
case LL_WARN : alp = ANDROID_LOG_WARN; break;
case LL_ERROR: alp = ANDROID_LOG_ERROR; break;
case LL_FATAL: alp = ANDROID_LOG_FATAL; break;
default: alp = ANDROID_LOG_FATAL;
}
__android_log_vprint(alp, "SuperTuxKart", format, va_list);
#else
// If not logged to file, set colours
if(!UserConfigParams::m_log_errors)
setTerminalColor((LogLevel)level);
static const char *names[] = {"verbose", "debug ", "info ",
"warn ", "error ", "fatal "};
printf("[%s] %s: ", names[level], component);
vprintf(format, va_list);
if(!UserConfigParams::m_log_errors)
resetTerminalColor();
#endif
} // printMessage

96
src/utils/log.hpp Normal file
View File

@ -0,0 +1,96 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_LOG_HPP
#define HEADER_LOG_HPP
#include <stdarg.h>
#ifdef __GNUC__
# define VALIST __gnuc_va_list
#else
# define VALIST char*
#endif
class Log
{
public:
/** The various log levels used in STK. */
enum LogLevel { LL_VERBOSE,
LL_DEBUG,
LL_INFO,
LL_WARN,
LL_ERROR,
LL_FATAL
};
private:
/** Which message level to print. */
static LogLevel m_min_log_level;
/** If set this will disable coloring of log messages. */
static bool m_no_colors;
static void setTerminalColor(LogLevel level);
static void resetTerminalColor();
public:
static void printMessage(int level, const char *component,
const char *format, VALIST va_list);
// ------------------------------------------------------------------------
/** A simple macro to define the various log functions. */
#define LOG(NAME, LEVEL) \
static void NAME(const char *component, const char *format, ...) \
{ \
if(LEVEL < m_min_log_level) return; \
va_list args; \
va_start(args, format); \
printMessage(LEVEL, component, format, args); \
va_end(args); \
}
LOG(verbose, LL_VERBOSE);
LOG(debug, LL_DEBUG);
LOG(info, LL_INFO);
LOG(warn, LL_WARN);
LOG(error, LL_ERROR);
LOG(fatal, LL_FATAL);
// ------------------------------------------------------------------------
/** Defines the minimum log level to be displayed. */
static void setLogLevel(int n)
{
if(n<0 || n>LL_FATAL)
{
warn("Log", "Log level %d not in range [%d-%d] - ignored.\n",
n, LL_VERBOSE, LL_FATAL);
return;
}
m_min_log_level = (LogLevel)n;
} // setLogLevel
// ------------------------------------------------------------------------
/** Disable coloring of log messages. */
static void disableColor()
{
m_no_colors = true;
} // disableColor
}; // Log
#endif

View File

@ -40,6 +40,7 @@
#include "io/file_manager.hpp"
#include "utils/constants.hpp"
#include "utils/log.hpp"
#include "utils/utf8.h"
@ -186,13 +187,14 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
char c[1024];
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME,
c, 1024);
printf("[translate] GetLocaleInfo langname returns '%s'.\n", c);
Log::verbose("[translate] GetLocaleInfo langname returns '%s'.\n",
c);
if(c[0])
{
language = c;
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME,
c, 1024);
printf("[translate] GetLocaleInfo tryname returns '%s'.\n", c);
Log::verbose("[translate] GetLocaleInfo tryname returns '%s'.\n", c);
if(c[0]) language += std::string("_")+c;
} // if c[0]
#endif
@ -202,7 +204,8 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
if (language != "")
{
std::cout << "[translate] Env var LANGUAGE = '"<<language<<"'\n";
Log::verbose("[translate] Env var LANGUAGE = '%s'.\n",
language.c_str());
if (language.find(":") != std::string::npos)
{
@ -214,9 +217,8 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
l = Language::from_env(langs[curr]);
if (l)
{
std::cout << "[translate] Env var LANGUAGE = '"
<< language << "', which corresponds to '"
<< l.get_name() << "'\n",
Log::verbose("[translate] Language '%s'.\n",
l.get_name().c_str());
m_dictionary = m_dictionary_manager.get_dictionary(l);
break;
}
@ -231,9 +233,8 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
}
else
{
std::cout << "[translate] Env var LANGUAGE = '" << language
<< "', which corresponds to '"
<< Language::from_env(language).get_name() << "'\n";
Log::verbose("[translate] Language '%s'.\n",
Language::from_env(language).get_name().c_str());
m_current_language_name = Language::from_env(language).get_name() ;