diff options
| author | Spp <spp@jorge.gr> | 2012-08-03 14:20:18 +0200 |
|---|---|---|
| committer | Spp <spp@jorge.gr> | 2012-08-03 14:20:18 +0200 |
| commit | 55ce180f2867700b28921d99f9a0cb9c83330c91 (patch) | |
| tree | c563db507cce44b680996d42148185cb1512188c /src/server/shared | |
| parent | f85908869986eab0b645f0a697028bcceba7778c (diff) | |
Core/Logging: Add Asyncronous logging with Loggers ("What to log") and Appenders ("Where to log") system. Will allow to select to full log some parts of core while others are not even logged.
- Logging System is asyncronous to improve performance.
- Each msg and Logger has a Log Type and Log Level assigned. Each msg is assigned the Logger of same Log Type or "root" Logger is selected if there is no Logger configured for the given Log Type
- Loggers have a list of Appenders to send the msg to. The Msg in the Logger is not sent to Appenders if the msg LogLevel is lower than Logger LogLevel.
- There are three (at the moment) types of Appenders: Console, File or DB (this is WIP, not working ATM). Msg is not written to the resource if msg LogLevel is lower than Appender LogLevel.
- Appender and Console Log levels can be changed while server is active with command '.set loglevel (a/l) name level'
Explanation of use with Sample config:
Appender.Console.Type=1 (1 = Console)
Appender.Console.Level=2 (2 = Debug)
Appender.Server.Type=2 (2 = File)
Appender.Server.Level=3 (3 = Info)
Appender.Server.File=Server.log
Appender.SQL.Type=2 (2 = File)
Appender.SQL.Level=1 (1 = Trace)
Appender.SQL.File=sql.log
Appenders=Console Server (NOTE: SQL has not been included here... that will make core ignore the config for "SQL" as it's not in this list)
Logger.root.Type=0 (0 = Default - if it's not created by config, server will create it with LogLevel = DISABLED)
Logger.root.Level=5 (5 = Error)
Logger.root.Appenders=Console
Logger.SQL.Type=26 (26 = SQL)
Logger.SQL.Level=3 (2 = Debug)
Logger.SQL.Appenders=Console Server SQL
Logger.SomeRandomName.Type=24 (24 = Guild)
Logger.SomeRandomName.Level=5 (5 = Error)
Loggers=root SQL SomeRandomName
* At loading Appender SQL will be ignored, as it's not present on "Appenders"
* sLog->outDebug(LOG_FILTER_GUILD, "Some log msg related to Guilds")
- Msg is sent to Logger of Type LOG_FILTER_GUILD (24). Logger with name SomeRandomName is found but it's LogLevel = 5 and Msg LogLevel=2... Msg is not logged
* sLog->outError(LOG_FILTER_GUILD, "Some error log msg related to Guilds")
- Msg is sent to Logger of Type LOG_FILTER_GUILD (24). Logger with name SomeRandomeName is found with proper LogLevel but Logger does not have any Appenders assigned to that logger... Msg is not logged
* sLog->outDebug(LOG_FILTER_SQL, "Some msg related to SQLs")
- Msg is sent to Logger SQL (matches type), as it matches LogLevel the msg is sent to Appenders Console, Server and SQL
- Appender Console has lower Log Level: Msg is logged to Console
- Appender Server has higher Log Level: Msg is not logged to file
- Appender SQL has lower Log Level: Msg is logged to file sql.log
* sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Some msg related to Battelgrounds")
- Msg is sent to Logger root (Type 0) as no Logger was found with Type LOG_FILTER_BATTLEGROUND (13). As Logger has higher LogLevel msg is not sent to any appender
* sLog->outError(LOG_FILTER_BATTLEGROUND, "Some error msg related to Battelgrounds")
- Msg is sent to Logger root (Type 0) as no Logger was found with Type LOG_FILTER_BATTLEGROUND (13). Msg has lower LogLevel and is sent to Appender Console
- Appender Console has lower LogLevel: Msg is logged to Console
Diffstat (limited to 'src/server/shared')
30 files changed, 1217 insertions, 1211 deletions
diff --git a/src/server/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index b82d86cc5d0..e0df22b88ae 100755 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -80,7 +80,7 @@ std::string GetStringDefault(const char* name, const std::string &def) { ACE_TString val; return GetValueHelper(name, val) ? val.c_str() : def; -}; +} bool GetBoolDefault(const char* name, bool def) { @@ -91,19 +91,19 @@ bool GetBoolDefault(const char* name, bool def) return (val == "true" || val == "TRUE" || val == "yes" || val == "YES" || val == "1"); -}; +} int GetIntDefault(const char* name, int def) { ACE_TString val; return GetValueHelper(name, val) ? atoi(val.c_str()) : def; -}; +} float GetFloatDefault(const char* name, float def) { ACE_TString val; return GetValueHelper(name, val) ? (float)atof(val.c_str()) : def; -}; +} const std::string & GetFilename() { diff --git a/src/server/shared/Configuration/Config.h b/src/server/shared/Configuration/Config.h index a870379881b..82e4d9bcce0 100755 --- a/src/server/shared/Configuration/Config.h +++ b/src/server/shared/Configuration/Config.h @@ -34,4 +34,3 @@ namespace ConfigMgr } #endif - diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.h b/src/server/shared/Cryptography/Authentication/AuthCrypt.h index 7081b4973d4..b40ce8ac40c 100755 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.h +++ b/src/server/shared/Cryptography/Authentication/AuthCrypt.h @@ -41,4 +41,3 @@ class AuthCrypt bool _initialized; }; #endif - diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h index c5b8b6f5a21..9965a5c1d71 100755 --- a/src/server/shared/DataStores/DBCStore.h +++ b/src/server/shared/DataStores/DBCStore.h @@ -117,7 +117,7 @@ class DBCStorage // Check if sql index pos is valid if (int32(result->GetFieldCount()-1) < sql->sqlIndexPos) { - sLog->outError("Invalid index pos for dbc:'%s'", sql->sqlTableName.c_str()); + sLog->outError(LOG_FILTER_GENERAL, "Invalid index pos for dbc:'%s'", sql->sqlTableName.c_str()); return false; } } @@ -148,7 +148,7 @@ class DBCStorage uint32 id = fields[sql->sqlIndexPos].GetUInt32(); if (indexTable.asT[id]) { - sLog->outError("Index %d already exists in dbc:'%s'", id, sql->sqlTableName.c_str()); + sLog->outError(LOG_FILTER_GENERAL, "Index %d already exists in dbc:'%s'", id, sql->sqlTableName.c_str()); return false; } indexTable.asT[id]=(T*)&sqlDataTable[offset]; @@ -203,7 +203,7 @@ class DBCStorage offset+=1; break; case FT_STRING: - sLog->outError("Unsupported data type in table '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); + sLog->outError(LOG_FILTER_GENERAL, "Unsupported data type in table '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); return false; case FT_SORT: break; @@ -215,13 +215,13 @@ class DBCStorage } else { - sLog->outError("Incorrect sql format string '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); + sLog->outError(LOG_FILTER_GENERAL, "Incorrect sql format string '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); return false; } } if (sqlColumnNumber != (result->GetFieldCount()-1)) { - sLog->outError("SQL and DBC format strings are not matching for table: '%s'", sql->sqlTableName.c_str()); + sLog->outError(LOG_FILTER_GENERAL, "SQL and DBC format strings are not matching for table: '%s'", sql->sqlTableName.c_str()); return false; } diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 314d196cc06..d86b99a062a 100755 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -64,7 +64,7 @@ class DatabaseWorkerPool bool res = true; _connectionInfo = MySQLConnectionInfo(infoString); - sLog->outSQLDriver("Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.", + sLog->outWarn(LOG_FILTER_SQL, "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.", GetDatabaseName(), async_threads, synch_threads); //! Open asynchronous connections (delayed operations) @@ -88,17 +88,17 @@ class DatabaseWorkerPool } if (res) - sLog->outSQLDriver("DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(), + sLog->outWarn(LOG_FILTER_SQL, "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(), (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC])); else - sLog->outError("DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile " + sLog->outError(LOG_FILTER_SQL, "DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile " "for specific errors.", GetDatabaseName()); return res; } void Close() { - sLog->outSQLDriver("Closing down DatabasePool '%s'.", GetDatabaseName()); + sLog->outWarn(LOG_FILTER_SQL, "Closing down DatabasePool '%s'.", GetDatabaseName()); //! Shuts down delaythreads for this connection pool by underlying deactivate(). //! The next dequeue attempt in the worker thread tasks will result in an error, @@ -114,7 +114,7 @@ class DatabaseWorkerPool t->Close(); //! Closes the actualy MySQL connection. } - sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", + sLog->outWarn(LOG_FILTER_SQL, "Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", GetDatabaseName()); //! Shut down the synchronous connections @@ -127,7 +127,7 @@ class DatabaseWorkerPool //! Deletes the ACE_Activation_Queue object and its underlying ACE_Message_Queue delete _queue; - sLog->outSQLDriver("All connections on DatabasePool '%s' closed.", GetDatabaseName()); + sLog->outWarn(LOG_FILTER_SQL, "All connections on DatabasePool '%s' closed.", GetDatabaseName()); } /** @@ -351,10 +351,10 @@ class DatabaseWorkerPool switch (transaction->GetSize()) { case 0: - sLog->outSQLDriver("Transaction contains 0 queries. Not executing."); + sLog->outWarn(LOG_FILTER_SQL, "Transaction contains 0 queries. Not executing."); return; case 1: - sLog->outSQLDriver("Warning: Transaction only holds 1 query, consider removing Transaction context in code."); + sLog->outWarn(LOG_FILTER_SQL, "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); break; default: break; diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h index bfa42dbe574..61e8fb7ccef 100755 --- a/src/server/shared/Database/Field.h +++ b/src/server/shared/Database/Field.h @@ -43,7 +43,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_TINY)) { - sLog->outSQLDriver("Warning: GetUInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetUInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -61,7 +61,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_TINY)) { - sLog->outSQLDriver("Warning: GetInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -79,7 +79,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR)) { - sLog->outSQLDriver("Warning: GetUInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetUInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -97,7 +97,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR)) { - sLog->outSQLDriver("Warning: GetInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -115,7 +115,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG)) { - sLog->outSQLDriver("Warning: GetUInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetUInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -133,7 +133,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG)) { - sLog->outSQLDriver("Warning: GetInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -151,7 +151,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT)) { - sLog->outSQLDriver("Warning: GetUInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetUInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -169,7 +169,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT)) { - sLog->outSQLDriver("Warning: GetInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type)); return 0; } #endif @@ -187,7 +187,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_FLOAT)) { - sLog->outSQLDriver("Warning: GetFloat() on non-float field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetFloat() on non-float field. Using type: %s.", FieldTypeToString(data.type)); return 0.0f; } #endif @@ -205,7 +205,7 @@ class Field #ifdef TRINITY_DEBUG if (!IsType(MYSQL_TYPE_DOUBLE)) { - sLog->outSQLDriver("Warning: GetDouble() on non-double field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Warning: GetDouble() on non-double field. Using type: %s.", FieldTypeToString(data.type)); return 0.0f; } #endif @@ -223,7 +223,7 @@ class Field #ifdef TRINITY_DEBUG if (IsNumeric()) { - sLog->outSQLDriver("Error: GetCString() on numeric field. Using type: %s.", FieldTypeToString(data.type)); + sLog->outWarn(LOG_FILTER_SQL, "Error: GetCString() on numeric field. Using type: %s.", FieldTypeToString(data.type)); return NULL; } #endif @@ -322,7 +322,7 @@ class Field MYSQL_TYPE_SET: */ default: - sLog->outSQLDriver("SQL::SizeForType(): invalid field type %u", uint32(field->type)); + sLog->outWarn(LOG_FILTER_SQL, "SQL::SizeForType(): invalid field type %u", uint32(field->type)); return 0; } } diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 7fb4a4f7025..324efab067e 100755 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -22,6 +22,8 @@ #include <winsock2.h> #endif #include <mysql.h> +#include <mysqld_error.h> +#include <errmsg.h> #include "MySQLConnection.h" #include "MySQLThreading.h" @@ -79,7 +81,7 @@ bool MySQLConnection::Open() mysqlInit = mysql_init(NULL); if (!mysqlInit) { - sLog->outError("Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str()); + sLog->outError(LOG_FILTER_SQL, "Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str()); return false; } @@ -123,13 +125,13 @@ bool MySQLConnection::Open() { if (!m_reconnecting) { - sLog->outSQLDriver("MySQL client library: %s", mysql_get_client_info()); - sLog->outSQLDriver("MySQL server ver: %s ", mysql_get_server_info(m_Mysql)); + sLog->outInfo(LOG_FILTER_SQL, "MySQL client library: %s", mysql_get_client_info()); + sLog->outInfo(LOG_FILTER_SQL, "MySQL server ver: %s ", mysql_get_server_info(m_Mysql)); if (mysql_get_server_version(m_Mysql) != mysql_get_client_version()) - sLog->outSQLDriver("[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements."); + sLog->outInfo(LOG_FILTER_SQL, "[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements."); } - sLog->outDetail("Connected to MySQL database at %s", m_connectionInfo.host.c_str()); + sLog->outInfo(LOG_FILTER_SQL, "Connected to MySQL database at %s", m_connectionInfo.host.c_str()); mysql_autocommit(m_Mysql, 1); // set connection properties to UTF8 to properly handle locales for different @@ -139,7 +141,7 @@ bool MySQLConnection::Open() } else { - sLog->outError("Could not connect to MySQL database at %s: %s\n", m_connectionInfo.host.c_str(), mysql_error(mysqlInit)); + sLog->outError(LOG_FILTER_SQL, "Could not connect to MySQL database at %s: %s\n", m_connectionInfo.host.c_str(), mysql_error(mysqlInit)); mysql_close(mysqlInit); return false; } @@ -159,26 +161,22 @@ bool MySQLConnection::Execute(const char* sql) return false; { - uint32 _s = 0; - if (sLog->GetSQLDriverQueryLogging()) - _s = getMSTime(); + uint32 _s = getMSTime(); if (mysql_query(m_Mysql, sql)) { uint32 lErrno = mysql_errno(m_Mysql); - sLog->outSQLDriver("SQL: %s", sql); - sLog->outSQLDriver("ERROR: [%u] %s", lErrno, mysql_error(m_Mysql)); + sLog->outInfo(LOG_FILTER_SQL, "SQL: %s", sql); + sLog->outError(LOG_FILTER_SQL, "[%u] %s", lErrno, mysql_error(m_Mysql)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return Execute(sql); // Try again return false; } - else if (sLog->GetSQLDriverQueryLogging()) - { - sLog->outSQLDriver("[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); - } + else + sLog->outDebug(LOG_FILTER_SQL, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); } return true; @@ -201,14 +199,12 @@ bool MySQLConnection::Execute(PreparedStatement* stmt) MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); - uint32 _s = 0; - if (sLog->GetSQLDriverQueryLogging()) - _s = getMSTime(); + uint32 _s = getMSTime(); if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) { uint32 lErrno = mysql_errno(m_Mysql); - sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + sLog->outError(LOG_FILTER_SQL, "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return Execute(stmt); // Try again @@ -220,7 +216,7 @@ bool MySQLConnection::Execute(PreparedStatement* stmt) if (mysql_stmt_execute(msql_STMT)) { uint32 lErrno = mysql_errno(m_Mysql); - sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + sLog->outError(LOG_FILTER_SQL, "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return Execute(stmt); // Try again @@ -229,8 +225,7 @@ bool MySQLConnection::Execute(PreparedStatement* stmt) return false; } - if (sLog->GetSQLDriverQueryLogging()) - sLog->outSQLDriver("[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); + sLog->outDebug(LOG_FILTER_SQL, "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); m_mStmt->ClearParameters(); return true; @@ -254,14 +249,12 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint6 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); - uint32 _s = 0; - if (sLog->GetSQLDriverQueryLogging()) - _s = getMSTime(); + uint32 _s = getMSTime(); if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) { uint32 lErrno = mysql_errno(m_Mysql); - sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); + sLog->outError(LOG_FILTER_SQL, "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again @@ -273,7 +266,7 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint6 if (mysql_stmt_execute(msql_STMT)) { uint32 lErrno = mysql_errno(m_Mysql); - sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", + sLog->outError(LOG_FILTER_SQL, "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) @@ -283,8 +276,7 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint6 return false; } - if (sLog->GetSQLDriverQueryLogging()) - sLog->outSQLDriver("[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); + sLog->outDebug(LOG_FILTER_SQL, "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); m_mStmt->ClearParameters(); @@ -319,25 +311,21 @@ bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD * return false; { - uint32 _s = 0; - if (sLog->GetSQLDriverQueryLogging()) - _s = getMSTime(); + uint32 _s = getMSTime(); if (mysql_query(m_Mysql, sql)) { uint32 lErrno = mysql_errno(m_Mysql); - sLog->outSQLDriver("SQL: %s", sql); - sLog->outSQLDriver("ERROR: [%u] %s", lErrno, mysql_error(m_Mysql)); + sLog->outInfo(LOG_FILTER_SQL, "SQL: %s", sql); + sLog->outError(LOG_FILTER_SQL, "[%u] %s", lErrno, mysql_error(m_Mysql)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again return false; } - else if (sLog->GetSQLDriverQueryLogging()) - { - sLog->outSQLDriver("[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); - } + else + sLog->outDebug(LOG_FILTER_SQL, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); *pResult = mysql_store_result(m_Mysql); *pRowCount = mysql_affected_rows(m_Mysql); @@ -393,7 +381,7 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) ASSERT(stmt); if (!Execute(stmt)) { - sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size()); + sLog->outWarn(LOG_FILTER_SQL, "Transaction aborted. %u queries not executed.", (uint32)queries.size()); RollbackTransaction(); return false; } @@ -405,7 +393,7 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) ASSERT(sql); if (!Execute(sql)) { - sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size()); + sLog->outWarn(LOG_FILTER_SQL, "Transaction aborted. %u queries not executed.", (uint32)queries.size()); RollbackTransaction(); return false; } @@ -428,7 +416,7 @@ MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) ASSERT(index < m_stmts.size()); MySQLPreparedStatement* ret = m_stmts[index]; if (!ret) - sLog->outSQLDriver("ERROR: Could not fetch prepared statement %u on database `%s`, connection type: %s.", + sLog->outError(LOG_FILTER_SQL, "Could not fetch prepared statement %u on database `%s`, connection type: %s.", index, m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); return ret; @@ -449,19 +437,19 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection return; } - MYSQL_STMT * stmt = mysql_stmt_init(m_Mysql); + MYSQL_STMT* stmt = mysql_stmt_init(m_Mysql); if (!stmt) { - sLog->outSQLDriver("[ERROR]: In mysql_stmt_init() id: %u, sql: \"%s\"", index, sql); - sLog->outSQLDriver("[ERROR]: %s", mysql_error(m_Mysql)); + sLog->outError(LOG_FILTER_SQL, "In mysql_stmt_init() id: %u, sql: \"%s\"", index, sql); + sLog->outError(LOG_FILTER_SQL, "%s", mysql_error(m_Mysql)); m_prepareError = true; } else { if (mysql_stmt_prepare(stmt, sql, static_cast<unsigned long>(strlen(sql)))) { - sLog->outSQLDriver("[ERROR]: In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql); - sLog->outSQLDriver("[ERROR]: %s", mysql_stmt_error(stmt)); + sLog->outError(LOG_FILTER_SQL, "In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql); + sLog->outError(LOG_FILTER_SQL, "%s", mysql_stmt_error(stmt)); mysql_stmt_close(stmt); m_prepareError = true; } @@ -493,19 +481,19 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) { switch (errNo) { - case 2006: // "MySQL server has gone away" - case 2013: // "Lost connection to MySQL server during query" - case 2048: // "Invalid connection handle" - case 2055: // "Lost connection to MySQL server at '%s', system error: %d" + case CR_SERVER_GONE_ERROR: + case CR_SERVER_LOST: + case CR_INVALID_CONN_HANDLE: + case CR_SERVER_LOST_EXTENDED: { m_reconnecting = true; uint64 oldThreadId = mysql_thread_id(GetHandle()); mysql_close(GetHandle()); if (this->Open()) // Don't remove 'this' pointer unless you want to skip loading all prepared statements.... { - sLog->outSQLDriver("Connection to the MySQL server is active."); + sLog->outInfo(LOG_FILTER_SQL, "Connection to the MySQL server is active."); if (oldThreadId != mysql_thread_id(GetHandle())) - sLog->outSQLDriver("Successfully reconnected to %s @%s:%s (%s).", + sLog->outInfo(LOG_FILTER_SQL, "Successfully reconnected to %s @%s:%s (%s).", m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); @@ -518,21 +506,23 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) return _HandleMySQLErrno(lErrno); // Call self (recursive) } - case 1213: // "Deadlock found when trying to get lock; try restarting transaction" + case ER_LOCK_DEADLOCK: return false; // Implemented in TransactionTask::Execute and DatabaseWorkerPool<T>::DirectCommitTransaction // Query related errors - skip query - case 1058: // "Column count doesn't match value count" - case 1062: // "Duplicate entry '%s' for key '%d'" + case ER_WRONG_VALUE_COUNT: + case ER_DUP_ENTRY: return false; // Outdated table or database structure - terminate core - case 1054: // "Unknown column '%s' in '%s'" - case 1146: // "Table '%s' doesn't exist" - WPFatal(!errNo, "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders."); + case ER_BAD_FIELD_ERROR: + case ER_NO_SUCH_TABLE: + sLog->outError(LOG_FILTER_SQL, "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders."); + ACE_OS::sleep(10); + std::abort(); return false; default: - sLog->outSQLDriver("Unhandled MySQL errno %u. Unexpected behaviour possible.", errNo); + sLog->outError(LOG_FILTER_SQL, "Unhandled MySQL errno %u. Unexpected behaviour possible.", errNo); return false; } } diff --git a/src/server/shared/Database/MySQLThreading.h b/src/server/shared/Database/MySQLThreading.h index 2004ee9826c..038ec4ee794 100755 --- a/src/server/shared/Database/MySQLThreading.h +++ b/src/server/shared/Database/MySQLThreading.h @@ -33,7 +33,7 @@ class MySQL static void Thread_Init() { mysql_thread_init(); - sLog->outSQLDriver("Core thread with ID ["UI64FMTD"] initializing MySQL thread.", + sLog->outWarn(LOG_FILTER_SQL, "Core thread with ID ["UI64FMTD"] initializing MySQL thread.", (uint64)ACE_Based::Thread::currentId()); } @@ -44,7 +44,7 @@ class MySQL static void Thread_End() { mysql_thread_end(); - sLog->outSQLDriver("Core thread with ID ["UI64FMTD"] shutting down MySQL thread.", + sLog->outWarn(LOG_FILTER_SQL, "Core thread with ID ["UI64FMTD"] shutting down MySQL thread.", (uint64)ACE_Based::Thread::currentId()); } diff --git a/src/server/shared/Database/PreparedStatement.cpp b/src/server/shared/Database/PreparedStatement.cpp index 58aa2bd3aa0..a72532e928b 100755 --- a/src/server/shared/Database/PreparedStatement.cpp +++ b/src/server/shared/Database/PreparedStatement.cpp @@ -78,7 +78,7 @@ void PreparedStatement::BindParameters() } #ifdef _DEBUG if (i < m_stmt->m_paramCount) - sLog->outSQLDriver("[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", m_index); + sLog->outWarn(LOG_FILTER_SQL, "[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", m_index); #endif } @@ -237,7 +237,7 @@ bool MySQLPreparedStatement::CheckValidIndex(uint8 index) return false; if (m_paramsSet[index]) - sLog->outSQLDriver("[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index); + sLog->outWarn(LOG_FILTER_SQL, "[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index); return true; } diff --git a/src/server/shared/Database/QueryHolder.cpp b/src/server/shared/Database/QueryHolder.cpp index a3602531205..99772c7e323 100755 --- a/src/server/shared/Database/QueryHolder.cpp +++ b/src/server/shared/Database/QueryHolder.cpp @@ -24,7 +24,7 @@ bool SQLQueryHolder::SetQuery(size_t index, const char *sql) { if (m_queries.size() <= index) { - sLog->outError("Query index (%zu) out of range (size: %u) for query: %s", index, (uint32)m_queries.size(), sql); + sLog->outError(LOG_FILTER_SQL, "Query index (%zu) out of range (size: %u) for query: %s", index, (uint32)m_queries.size(), sql); return false; } @@ -44,7 +44,7 @@ bool SQLQueryHolder::SetPQuery(size_t index, const char *format, ...) { if (!format) { - sLog->outError("Query (index: %zu) is empty.", index); + sLog->outError(LOG_FILTER_SQL, "Query (index: %zu) is empty.", index); return false; } @@ -56,7 +56,7 @@ bool SQLQueryHolder::SetPQuery(size_t index, const char *format, ...) if (res == -1) { - sLog->outError("SQL Query truncated (and not execute) for format: %s", format); + sLog->outError(LOG_FILTER_SQL, "SQL Query truncated (and not execute) for format: %s", format); return false; } @@ -67,7 +67,7 @@ bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt) { if (m_queries.size() <= index) { - sLog->outError("Query index (%zu) out of range (size: %u) for prepared statement", index, (uint32)m_queries.size()); + sLog->outError(LOG_FILTER_SQL, "Query index (%zu) out of range (size: %u) for prepared statement", index, (uint32)m_queries.size()); return false; } diff --git a/src/server/shared/Database/QueryResult.cpp b/src/server/shared/Database/QueryResult.cpp index 95034387089..cb21c088d00 100755 --- a/src/server/shared/Database/QueryResult.cpp +++ b/src/server/shared/Database/QueryResult.cpp @@ -59,7 +59,7 @@ m_length(NULL) //- This is where we store the (entire) resultset if (mysql_stmt_store_result(m_stmt)) { - sLog->outSQLDriver("%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt)); + sLog->outWarn(LOG_FILTER_SQL, "%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt)); return; } @@ -86,7 +86,7 @@ m_length(NULL) //- This is where we bind the bind the buffer to the statement if (mysql_stmt_bind_result(m_stmt, m_rBind)) { - sLog->outSQLDriver("%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt)); + sLog->outWarn(LOG_FILTER_SQL, "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt)); delete[] m_rBind; delete[] m_isNull; delete[] m_length; diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h index 48a8bda32ed..6ce3d926f4c 100755 --- a/src/server/shared/Debugging/Errors.h +++ b/src/server/shared/Debugging/Errors.h @@ -24,10 +24,10 @@ #include <ace/Stack_Trace.h> #include <ace/OS_NS_unistd.h> -#define WPAssert(assertion) { if (!(assertion)) { ACE_Stack_Trace st; sLog->outError("\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } } -#define WPError(assertion, errmsg) { if (!(assertion)) { sLog->outError("%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); *((volatile int*)NULL) = 0; } } -#define WPWarning(assertion, errmsg) { if (!(assertion)) { sLog->outError("\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); } } -#define WPFatal(assertion, errmsg) { if (!(assertion)) { sLog->outError("\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); ACE_OS::sleep(10); *((volatile int*)NULL) = 0; } } +#define WPAssert(assertion) { if (!(assertion)) { ACE_Stack_Trace st; sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } } +#define WPError(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); *((volatile int*)NULL) = 0; } } +#define WPWarning(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); } } +#define WPFatal(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); ACE_OS::sleep(10); *((volatile int*)NULL) = 0; } } #define ASSERT WPAssert #endif diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp new file mode 100644 index 00000000000..38d58f1ffb5 --- /dev/null +++ b/src/server/shared/Logging/Appender.cpp @@ -0,0 +1,153 @@ +#include "Appender.h" +#include "Common.h" + +std::string LogMessage::getTimeStr(time_t time) +{ + tm* aTm = localtime(&time); + char buf[20]; + snprintf(buf, 20, "%04d-%02d-%02d_%02d:%02d:%02d", aTm->tm_year+1900, aTm->tm_mon+1, aTm->tm_mday, aTm->tm_hour, aTm->tm_min, aTm->tm_sec); + return std::string(buf); +} + +std::string LogMessage::getTimeStr() +{ + return getTimeStr(mtime); +} + +Appender::Appender(uint8 _id, std::string const& _name, AppenderType _type /* = APPENDER_NONE*/, LogLevel _level /* = LOG_LEVEL_DISABLED */): +id(_id), name(_name), type(_type), level(_level) +{ +} + +Appender::~Appender() +{ +} + +uint8 Appender::getId() const +{ + return id; +} + +std::string const& Appender::getName() const +{ + return name; +} + +AppenderType Appender::getType() const +{ + return type; +} + +LogLevel Appender::getLogLevel() const +{ + return level; +} + +void Appender::setLogLevel(LogLevel _level) +{ + level = _level; +} + +void Appender::write(LogMessage& message) +{ + if (level && level <= message.level) + _write(message); + //else fprintf(stderr, "Appender::write: Appender %s, Level %s. Msg %s Level %s Type %s WRONG LEVEL MASK\n", getName().c_str(), getLogLevelString(level), message.text.c_str(), getLogLevelString(message.level), getLogFilterTypeString(message.type)); // DEBUG - RemoveMe +} + +const char* Appender::getLogLevelString(LogLevel level) +{ + switch (level) + { + case LOG_LEVEL_FATAL: + return "FATAL"; + case LOG_LEVEL_ERROR: + return "ERROR"; + case LOG_LEVEL_WARN: + return "WARN"; + case LOG_LEVEL_INFO: + return "INFO"; + case LOG_LEVEL_DEBUG: + return "DEBUG"; + case LOG_LEVEL_TRACE: + return "TRACE"; + default: + return "DISABLED"; + } +} + +char const* Appender::getLogFilterTypeString(LogFilterType type) +{ + switch (type) + { + case LOG_FILTER_GENERAL: + return "GENERAL"; + case LOG_FILTER_UNITS: + return "UNITS"; + case LOG_FILTER_PETS: + return "PETS"; + case LOG_FILTER_VEHICLES: + return "VEHICLES"; + case LOG_FILTER_TSCR: + return "TSCR"; + case LOG_FILTER_DATABASE_AI: + return "DATABASE_AI"; + case LOG_FILTER_MAPSCRIPTS: + return "MAPSCRIPTS"; + case LOG_FILTER_NETWORKIO: + return "NETWORKIO"; + case LOG_FILTER_SPELLS_AURAS: + return "SPELLS_AURAS"; + case LOG_FILTER_ACHIEVEMENTSYS: + return "ACHIEVEMENTSYS"; + case LOG_FILTER_CONDITIONSYS: + return "CONDITIONSYS"; + case LOG_FILTER_POOLSYS: + return "POOLSYS"; + case LOG_FILTER_AUCTIONHOUSE: + return "AUCTIONHOUSE"; + case LOG_FILTER_BATTLEGROUND: + return "BATTLEGROUND"; + case LOG_FILTER_OUTDOORPVP: + return "OUTDOORPVP"; + case LOG_FILTER_CHATSYS: + return "CHATSYS"; + case LOG_FILTER_LFG: + return "LFG"; + case LOG_FILTER_MAPS: + return "MAPS"; + case LOG_FILTER_PLAYER: + return "PLAYER"; + case LOG_FILTER_PLAYER_LOADING: + return "PLAYER_LOADING"; + case LOG_FILTER_PLAYER_ITEMS: + return "PLAYER_ITEMS"; + case LOG_FILTER_PLAYER_SKILLS: + return "PLAYER_SKILLS"; + case LOG_FILTER_PLAYER_CHATLOG: + return "PLAYER_CHATLOG"; + case LOG_FILTER_LOOT: + return "LOOT"; + case LOG_FILTER_GUILD: + return "GUILD"; + case LOG_FILTER_TRANSPORTS: + return "TRANSPORTS"; + case LOG_FILTER_SQL: + return "SQL"; + case LOG_FILTER_GMCOMMAND: + return "GMCOMMAND"; + case LOG_FILTER_REMOTECOMMAND: + return "REMOTECOMMAND"; + case LOG_FILTER_WARDEN: + return "WARDEN"; + case LOG_FILTER_AUTHSERVER: + return "AUTHSERVER"; + case LOG_FILTER_WORLDSERVER: + return "WORLDSERVER"; + case LOG_FILTER_GAMEEVENTS: + return "GAMEEVENTS"; + default: + break; + } + return "???"; +} diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h new file mode 100644 index 00000000000..992554d59aa --- /dev/null +++ b/src/server/shared/Logging/Appender.h @@ -0,0 +1,115 @@ +#ifndef APPENDER_H +#define APPENDER_H + +#include "Define.h" + +#include <string> +#include <map> + +enum LogFilterType +{ + LOG_FILTER_GENERAL, // This one should only be used inside Log.cpp + LOG_FILTER_UNITS, // Anything related to units that doesn't fit in other categories. ie. creature formations + LOG_FILTER_PETS, + LOG_FILTER_VEHICLES, + LOG_FILTER_TSCR, // C++ AI, instance scripts, etc. + LOG_FILTER_DATABASE_AI, // SmartAI, EventAI, Creature* * AI + LOG_FILTER_MAPSCRIPTS, + LOG_FILTER_NETWORKIO, + LOG_FILTER_SPELLS_AURAS, + LOG_FILTER_ACHIEVEMENTSYS, + LOG_FILTER_CONDITIONSYS, + LOG_FILTER_POOLSYS, + LOG_FILTER_AUCTIONHOUSE, + LOG_FILTER_BATTLEGROUND, + LOG_FILTER_OUTDOORPVP, + LOG_FILTER_CHATSYS, + LOG_FILTER_LFG, + LOG_FILTER_MAPS, + LOG_FILTER_PLAYER, // Any player log that does not fit in other player filters + LOG_FILTER_PLAYER_LOADING, // Debug output from Player::_Load functions + LOG_FILTER_PLAYER_ITEMS, + LOG_FILTER_PLAYER_SKILLS, + LOG_FILTER_PLAYER_CHATLOG, + LOG_FILTER_LOOT, + LOG_FILTER_GUILD, + LOG_FILTER_TRANSPORTS, + LOG_FILTER_SQL, + LOG_FILTER_GMCOMMAND, + LOG_FILTER_REMOTECOMMAND, + LOG_FILTER_WARDEN, + LOG_FILTER_AUTHSERVER, + LOG_FILTER_WORLDSERVER, + LOG_FILTER_GAMEEVENTS, + LOG_FILTER_CALENDAR +}; + +const uint8 MaxLogFilter = uint8(LOG_FILTER_CALENDAR) + 1; + +// Values assigned have their equivalent in enum ACE_Log_Priority +enum LogLevel +{ + LOG_LEVEL_DISABLED = 0, + LOG_LEVEL_TRACE = 1, + LOG_LEVEL_DEBUG = 2, + LOG_LEVEL_INFO = 3, + LOG_LEVEL_WARN = 4, + LOG_LEVEL_ERROR = 5, + LOG_LEVEL_FATAL = 6, +}; + +const uint8 MaxLogLevels = 6; + +enum AppenderType +{ + APPENDER_NONE, + APPENDER_CONSOLE, + APPENDER_FILE, + APPENDER_DB, +}; + +struct LogMessage +{ + LogMessage(LogLevel _level, LogFilterType _type, std::string _text): level(_level), type(_type), text(_text) + { + mtime = time(NULL); + } + + static std::string getTimeStr(time_t time); + std::string getTimeStr(); + + LogLevel level; + LogFilterType type; + std::string text; + uint32 param1; + time_t mtime; +}; + +class Appender +{ + public: + Appender(uint8 _id, std::string const& name, AppenderType type = APPENDER_NONE, LogLevel level = LOG_LEVEL_DISABLED); + virtual ~Appender(); + + uint8 getId() const; + std::string const& getName() const; + AppenderType getType() const; + LogLevel getLogLevel() const; + + void setLogLevel(LogLevel); + void write(LogMessage& message); + static const char* getLogLevelString(LogLevel level); + static const char* getLogFilterTypeString(LogFilterType type); + + private: + virtual void _write(LogMessage& /*message*/) {}; + + uint8 id; + std::string name; + AppenderType type; + LogLevel level; +}; + +typedef std::map<uint8, Appender*> AppenderMap; + +#endif diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp new file mode 100644 index 00000000000..ad81a883bfa --- /dev/null +++ b/src/server/shared/Logging/AppenderConsole.cpp @@ -0,0 +1,174 @@ +#include "AppenderConsole.h" +#include "Config.h" +#include "Util.h" + +#include <sstream> + +AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level): +Appender(id, name, APPENDER_CONSOLE, level), _colored(false), _colors() +{ +} + +void AppenderConsole::InitColors(std::string const& str) +{ + if (str.empty()) + { + _colored = false; + return; + } + + int color[MaxLogLevels]; + + std::istringstream ss(str); + + for (uint8 i = 0; i < MaxLogLevels; ++i) + { + ss >> color[i]; + + if (!ss) + return; + + if (color[i] < 0 || color[i] >= MaxColors) + return; + } + + for (uint8 i = 0; i < MaxLogLevels; ++i) + _colors[i] = ColorTypes(color[i]); + + _colored = true; +} + +void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color) +{ + #if PLATFORM == PLATFORWINDOWS + static WORD WinColorFG[MaxColors] = + { + 0, // BLACK + FOREGROUND_RED, // RED + FOREGROUND_GREEN, // GREEN + FOREGROUND_RED | FOREGROUND_GREEN, // BROWN + FOREGROUND_BLUE, // BLUE + FOREGROUND_RED | FOREGROUND_BLUE, // MAGENTA + FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // WHITE + // YELLOW + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, + // RED_BOLD + FOREGROUND_RED | FOREGROUND_INTENSITY, + // GREEN_BOLD + FOREGROUND_GREEN | FOREGROUND_INTENSITY, + FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD + // MAGENTA_BOLD + FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + // CYAN_BOLD + FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + // WHITE_BOLD + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY + }; + + HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + SetConsoleTextAttribute(hConsole, WinColorFG[color]); + #else + enum ANSITextAttr + { + TA_NORMAL = 0, + TA_BOLD = 1, + TA_BLINK = 5, + TA_REVERSE = 7 + }; + + enum ANSIFgTextAttr + { + FG_BLACK = 30, + FG_RED, + FG_GREEN, + FG_BROWN, + FG_BLUE, + FG_MAGENTA, + FG_CYAN, + FG_WHITE, + FG_YELLOW + }; + + enum ANSIBgTextAttr + { + BG_BLACK = 40, + BG_RED, + BG_GREEN, + BG_BROWN, + BG_BLUE, + BG_MAGENTA, + BG_CYAN, + BG_WHITE + }; + + static uint8 UnixColorFG[MaxColors] = + { + FG_BLACK, // BLACK + FG_RED, // RED + FG_GREEN, // GREEN + FG_BROWN, // BROWN + FG_BLUE, // BLUE + FG_MAGENTA, // MAGENTA + FG_CYAN, // CYAN + FG_WHITE, // WHITE + FG_YELLOW, // YELLOW + FG_RED, // LRED + FG_GREEN, // LGREEN + FG_BLUE, // LBLUE + FG_MAGENTA, // LMAGENTA + FG_CYAN, // LCYAN + FG_WHITE // LWHITE + }; + + fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < MaxColors ? ";1" : "")); + #endif +} + +void AppenderConsole::ResetColor(bool stdout_stream) +{ + #if PLATFORM == PLATFORWINDOWS + HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); + #else + fprintf((stdout_stream ? stdout : stderr), "\x1b[0m"); + #endif +} + +void AppenderConsole::_write(LogMessage& message) +{ + bool stdout_stream = message.level == LOG_LEVEL_ERROR || message.level == LOG_LEVEL_FATAL; + + if (_colored) + { + uint8 index; + switch (message.level) + { + case LOG_LEVEL_TRACE: + index = 5; + break; + case LOG_LEVEL_DEBUG: + index = 4; + break; + case LOG_LEVEL_INFO: + index = 3; + break; + case LOG_LEVEL_WARN: + index = 2; + break; + case LOG_LEVEL_FATAL: + index = 0; + break; + case LOG_LEVEL_ERROR: // No break on purpose + default: + index = 1; + break; + } + + SetColor(stdout_stream, _colors[index]); + utf8printf(stdout_stream ? stdout : stderr, "%s %-5s [%-15s] %s", message.getTimeStr().c_str(), Appender::getLogLevelString(message.level), Appender::getLogFilterTypeString(message.type), message.text.c_str()); + ResetColor(stdout_stream); + } + else + utf8printf(stdout_stream ? stdout : stderr, "%s %-5s [%-15s] %s", message.getTimeStr().c_str(), Appender::getLogLevelString(message.level), Appender::getLogFilterTypeString(message.type), message.text.c_str()); +} diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h new file mode 100644 index 00000000000..a9f46cf9c4a --- /dev/null +++ b/src/server/shared/Logging/AppenderConsole.h @@ -0,0 +1,42 @@ +#ifndef APPENDERCONSOLE_H +#define APPENDERCONSOLE_H + +#include "Appender.h" +#include <string> + +enum ColorTypes +{ + BLACK, + RED, + GREEN, + BROWN, + BLUE, + MAGENTA, + CYAN, + GREY, + YELLOW, + LRED, + LGREEN, + LBLUE, + LMAGENTA, + LCYAN, + WHITE +}; + +const uint8 MaxColors = uint8(WHITE) + 1; + +class AppenderConsole: public Appender +{ + public: + AppenderConsole(uint8 _id, std::string const& name, LogLevel level); + void InitColors(const std::string& init_str); + + private: + void SetColor(bool stdout_stream, ColorTypes color); + void ResetColor(bool stdout_stream); + void _write(LogMessage& message); + bool _colored; + ColorTypes _colors[MaxLogLevels]; +}; + +#endif diff --git a/src/server/shared/Logging/AppenderDB.cpp b/src/server/shared/Logging/AppenderDB.cpp new file mode 100644 index 00000000000..6f3737adf4d --- /dev/null +++ b/src/server/shared/Logging/AppenderDB.cpp @@ -0,0 +1,30 @@ +#include "AppenderDB.h" + +/* FIXME +#include "DatabaseWorkerPool.h" +#include "Implementation/LoginDatabase.h" // For logging +extern DatabaseWorkerPool LoginDatabase; +*/ + +AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level, uint8 realmId): +Appender(id, name, APPENDER_DB, level), realm(realmId), enable(false) +{ +} + +AppenderDB::~AppenderDB() +{ +} + +void AppenderDB::_write(LogMessage& /*message*/) +{ +/* FIXME + if (enable) + LoginDatabase.PExecute("INSERT INTO logs (time, realm, type, severity, string) " + "VALUES (" UI64FMTD ", %u, %u, '%s');", message.mtime, realm, message.type, message.level, message.text.c_str()); +*/ +} + +void AppenderDB::setEnable(bool _enable) +{ + enable = _enable; +} diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h new file mode 100644 index 00000000000..ca15fc1a1d5 --- /dev/null +++ b/src/server/shared/Logging/AppenderDB.h @@ -0,0 +1,19 @@ +#ifndef APPENDERDB_H +#define APPENDERDB_H + +#include "Appender.h" + +class AppenderDB: public Appender +{ + public: + AppenderDB(uint8 _id, std::string const& _name, LogLevel level, uint8 realmId); + ~AppenderDB(); + void setEnable(bool enable); + + private: + uint8 realm; + bool enable; + void _write(LogMessage& message); +}; + +#endif diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp new file mode 100644 index 00000000000..30c1f271c96 --- /dev/null +++ b/src/server/shared/Logging/AppenderFile.cpp @@ -0,0 +1,54 @@ +#include "AppenderFile.h" +#include "Common.h" + +AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, const char* _filename, const char* _mode, bool _backup) + : Appender(id, name, APPENDER_FILE, level) + , filename(_filename) + , mode(_mode) + , backup(_backup) +{ + dynamicName = std::string::npos != filename.find("%u"); + if (!dynamicName) + logfile = OpenFile(_filename, _mode, _backup); +} + +AppenderFile::~AppenderFile() +{ + if (logfile) + { + fclose(logfile); + logfile = NULL; + } +} + +void AppenderFile::_write(LogMessage& message) +{ + if (dynamicName) + { + char namebuf[TRINITY_PATH_MAX]; + snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1); + logfile = OpenFile(namebuf, mode, backup); + } + + if (logfile) + { + fprintf(logfile, "%s %-5s [%-15s] %s", message.getTimeStr().c_str(), Appender::getLogLevelString(message.level), Appender::getLogFilterTypeString(message.type), message.text.c_str()); + + fflush(logfile); + + if (dynamicName) + fclose(logfile); + } +} + +FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup) +{ + if (mode == "w" && backup) + { + std::string newName(filename); + newName.push_back('.'); + newName.append(LogMessage::getTimeStr(time(NULL))); + rename(filename.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore + } + return fopen(filename.c_str(), mode.c_str()); +} diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h new file mode 100644 index 00000000000..a01ea947334 --- /dev/null +++ b/src/server/shared/Logging/AppenderFile.h @@ -0,0 +1,22 @@ +#ifndef APPENDERFILE_H +#define APPENDERFILE_H + +#include "Appender.h" + +class AppenderFile: public Appender +{ + public: + AppenderFile(uint8 _id, std::string const& _name, LogLevel level, const char* filename, const char* mode, bool backup); + ~AppenderFile(); + FILE* OpenFile(std::string const& _name, std::string const& _mode, bool _backup); + + private: + void _write(LogMessage& message); + FILE* logfile; + std::string filename; + std::string mode; + bool dynamicName; + bool backup; +}; + +#endif diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index 79eab053d08..17c6df44125 100755 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * * 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 @@ -16,343 +16,246 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Common.h" #include "Log.h" -#include "Configuration/Config.h" -#include "Util.h" +#include "Common.h" +#include "Config.h" -#include "Implementation/LoginDatabase.h" // For logging -extern LoginDatabaseWorkerPool LoginDatabase; +#include "AppenderConsole.h" +#include "AppenderFile.h" +#include "AppenderDB.h" +#include "LogOperation.h" -#include <stdarg.h> -#include <stdio.h> +#include <cstdarg> +#include <cstdio> +#include <sstream> -Log::Log() : - raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL), - dberLogfile(NULL), chatLogfile(NULL), arenaLogFile(NULL), sqlLogFile(NULL), sqlDevLogFile(NULL), wardenLogFile(NULL), - m_gmlog_per_account(false), m_enableLogDBLater(false), - m_enableLogDB(false), m_colored(false) +Log::Log() { - Initialize(); + SetRealmID(0); + AppenderId = 0; + /// Common log files data + m_logsDir = ConfigMgr::GetStringDefault("LogsDir", ""); + if (!m_logsDir.empty()) + if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\')) + m_logsDir.push_back('/'); + + m_logsTimestamp = "_" + GetTimestampStr(); + + ReadAppendersFromConfig(); + ReadLoggersFromConfig(); + worker = new LogWorker(); } Log::~Log() { - if (logfile != NULL) - fclose(logfile); - logfile = NULL; - - if (gmLogfile != NULL) - fclose(gmLogfile); - gmLogfile = NULL; - - if (charLogfile != NULL) - fclose(charLogfile); - charLogfile = NULL; - - if (dberLogfile != NULL) - fclose(dberLogfile); - dberLogfile = NULL; - - if (raLogfile != NULL) - fclose(raLogfile); - raLogfile = NULL; - - if (chatLogfile != NULL) - fclose(chatLogfile); - chatLogfile = NULL; - - if (arenaLogFile != NULL) - fclose(arenaLogFile); - arenaLogFile = NULL; - - if (sqlLogFile != NULL) - fclose(sqlLogFile); - sqlLogFile = NULL; - - if (sqlDevLogFile != NULL) - fclose(sqlDevLogFile); - sqlDevLogFile = NULL; - - if (wardenLogFile != NULL) - fclose(wardenLogFile); - wardenLogFile = NULL; + Close(); } -void Log::SetLogLevel(char *Level) +uint8 Log::NextAppenderId() { - int32 NewLevel = atoi((char*)Level); - if (NewLevel < 0) - NewLevel = 0; - m_logLevel = NewLevel; - - outString("LogLevel is %u", m_logLevel); + return AppenderId++; } -void Log::SetLogFileLevel(char *Level) +int32 GetConfigIntDefault(std::string base, const char* name, int32 value) { - int32 NewLevel = atoi((char*)Level); - if (NewLevel < 0) - NewLevel = 0; - m_logFileLevel = NewLevel; + base.append(name); + return ConfigMgr::GetIntDefault(base.c_str(), value); +} - outString("LogFileLevel is %u", m_logFileLevel); +std::string GetConfigStringDefault(std::string base, const char* name, const char* value) +{ + base.append(name); + return ConfigMgr::GetStringDefault(base.c_str(), value); } -void Log::SetDBLogLevel(char *Level) +// Returns default logger if the requested logger is not found +Logger* Log::GetLoggerByType(LogFilterType filter) { - int32 NewLevel = atoi((char*)Level); - if (NewLevel < 0) - NewLevel = 0; - m_dbLogLevel = NewLevel; + LoggerMap::iterator it = loggers.begin(); + while (it != loggers.end() && it->second.getType() != filter) + ++it; - outString("DBLogLevel is %u", m_dbLogLevel); + return it == loggers.end() ? &(loggers[0]) : &(it->second); } -void Log::Initialize() +Appender* Log::GetAppenderByName(std::string const& name) { - /// Check whether we'll log GM commands/RA events/character outputs/chat stuffs - m_dbChar = ConfigMgr::GetBoolDefault("LogDB.Char", false); - m_dbRA = ConfigMgr::GetBoolDefault("LogDB.RA", false); - m_dbGM = ConfigMgr::GetBoolDefault("LogDB.GM", false); - m_dbChat = ConfigMgr::GetBoolDefault("LogDB.Chat", false); + AppenderMap::iterator it = appenders.begin(); + while (it != appenders.end() && it->second && it->second->getName() != name) + ++it; - /// Realm must be 0 by default - SetRealmID(0); + return it == appenders.end() ? NULL : it->second; +} - /// Common log files data - m_logsDir = ConfigMgr::GetStringDefault("LogsDir", ""); - if (!m_logsDir.empty()) - if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\')) - m_logsDir.push_back('/'); +void Log::CreateAppenderFromConfig(const char* name) +{ + if (!name || *name == '\0') + return; - m_logsTimestamp = "_" + GetTimestampStr(); + std::string base = "Appender."; + base.append(name); + base.push_back('.'); - /// Open specific log files - logfile = openLogFile("LogFile", "LogTimestamp", "w"); - InitColors(ConfigMgr::GetStringDefault("LogColors", "")); + LogLevel level = LogLevel(GetConfigIntDefault(base, "Level", 0)); + AppenderType type = AppenderType(GetConfigIntDefault(base, "Type", 0)); - m_gmlog_per_account = ConfigMgr::GetBoolDefault("GmLogPerAccount", false); - if (!m_gmlog_per_account) - gmLogfile = openLogFile("GMLogFile", "GmLogTimestamp", "a"); - else + switch(type) { - // GM log settings for per account case - m_gmlog_filename_format = ConfigMgr::GetStringDefault("GMLogFile", ""); - if (!m_gmlog_filename_format.empty()) + case APPENDER_CONSOLE: { - bool m_gmlog_timestamp = ConfigMgr::GetBoolDefault("GmLogTimestamp", false); + AppenderConsole* appender = new AppenderConsole(NextAppenderId(), name, level); + appenders[appender->getId()] = appender; - size_t dot_pos = m_gmlog_filename_format.find_last_of('.'); - if (dot_pos!=m_gmlog_filename_format.npos) - { - if (m_gmlog_timestamp) - m_gmlog_filename_format.insert(dot_pos, m_logsTimestamp); + appender->InitColors(GetConfigStringDefault(base, "Colors", "")); + //fprintf(stdout, "Log::CreateAppenderFromConfig: Created Appender %s (%u), Type CONSOLE, Mask %u\n", appender->getName().c_str(), appender->getId(), appender->getLogLevel()); // DEBUG - RemoveMe + break; + } + case APPENDER_FILE: + { + std::string filename = GetConfigStringDefault(base, "File", ""); + std::string mode = GetConfigStringDefault(base, "Mode", "a"); + std::string timestamp = GetConfigStringDefault(base, "Timestamp", ""); + bool backup = GetConfigIntDefault(base, "Backup", 0); - m_gmlog_filename_format.insert(dot_pos, "_#%u"); - } - else + if (!timestamp.empty()) { - m_gmlog_filename_format += "_#%u"; - - if (m_gmlog_timestamp) - m_gmlog_filename_format += m_logsTimestamp; + size_t dot_pos = filename.find_last_of("."); + if (dot_pos != filename.npos) + filename.insert(dot_pos, m_logsTimestamp); + else + filename += m_logsTimestamp; } - m_gmlog_filename_format = m_logsDir + m_gmlog_filename_format; + uint8 id = NextAppenderId(); + appenders[id] = new AppenderFile(id, name, level, filename.c_str(), mode.c_str(), backup); + //fprintf(stdout, "Log::CreateAppenderFromConfig: Created Appender %s (%u), Type FILE, Mask %u, File %s, Mode %s\n", name, id, level, filename.c_str(), mode.c_str()); // DEBUG - RemoveMe + break; } + case APPENDER_DB: // TODO Set realm! + { + uint8 id = NextAppenderId(); + appenders[id] = new AppenderDB(id, name, level, realm); + break; + } + default: + break; } +} + +void Log::CreateLoggerFromConfig(const char* name) +{ + if (!name || *name == '\0') + return; + + std::string base = "Logger."; + base.append(name); + base.push_back('.'); + + LogLevel level = LogLevel(GetConfigIntDefault(base, "Level", 0)); + int32 type = GetConfigIntDefault(base, "Type", -1); - charLogfile = openLogFile("CharLogFile", "CharLogTimestamp", "a"); - dberLogfile = openLogFile("DBErrorLogFile", NULL, "a"); - raLogfile = openLogFile("RaLogFile", NULL, "a"); - chatLogfile = openLogFile("ChatLogFile", "ChatLogTimestamp", "a"); - arenaLogFile = openLogFile("ArenaLogFile", NULL, "a"); - sqlLogFile = openLogFile("SQLDriverLogFile", NULL, "a"); - sqlDevLogFile = openLogFile("SQLDeveloperLogFile", NULL, "a"); - wardenLogFile = openLogFile("Warden.LogFile",NULL,"a"); - - // Main log file settings - m_logLevel = ConfigMgr::GetIntDefault("LogLevel", LOGL_NORMAL); - m_logFileLevel = ConfigMgr::GetIntDefault("LogFileLevel", LOGL_NORMAL); - m_dbLogLevel = ConfigMgr::GetIntDefault("DBLogLevel", LOGL_NORMAL); - m_sqlDriverQueryLogging = ConfigMgr::GetBoolDefault("SQLDriverQueryLogging", false); - - m_DebugLogMask = DebugLogFilters(ConfigMgr::GetIntDefault("DebugLogMask", LOG_FILTER_NONE)); - - // Char log settings - m_charLog_Dump = ConfigMgr::GetBoolDefault("CharLogDump", false); - m_charLog_Dump_Separate = ConfigMgr::GetBoolDefault("CharLogDump.Separate", false); - if (m_charLog_Dump_Separate) + if (type < 0) { - m_dumpsDir = ConfigMgr::GetStringDefault("CharLogDump.SeparateDir", ""); - if (!m_dumpsDir.empty()) - if ((m_dumpsDir.at(m_dumpsDir.length() - 1) != '/') && (m_dumpsDir.at(m_dumpsDir.length() - 1) != '\\')) - m_dumpsDir.push_back('/'); + fprintf(stderr, "Log::CreateLoggerFromConfig: Missing entry %sType in config. Logger ignored\n", name); + return; } -} -void Log::ReloadConfig() -{ - m_logLevel = ConfigMgr::GetIntDefault("LogLevel", LOGL_NORMAL); - m_logFileLevel = ConfigMgr::GetIntDefault("LogFileLevel", LOGL_NORMAL); - m_dbLogLevel = ConfigMgr::GetIntDefault("DBLogLevel", LOGL_NORMAL); + Logger& logger = loggers[type]; - m_DebugLogMask = DebugLogFilters(ConfigMgr::GetIntDefault("DebugLogMask", LOG_FILTER_NONE)); -} + if (!logger.getName().empty()) + fprintf(stderr, "Error while configuring Logger %s. Replacing (name: %s, Type: %u, Level: %u) with (name: %s, Type: %u, Level: %u)\n", + name, logger.getName().c_str(), logger.getType(), logger.getLogLevel(), name, type, level); -FILE* Log::openLogFile(char const* configFileName, char const* configTimeStampFlag, char const* mode) -{ - std::string logfn=ConfigMgr::GetStringDefault(configFileName, ""); - if (logfn.empty()) - return NULL; + logger.Create(name, LogFilterType(type), level); + //fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Type %u, mask %u\n", name, LogFilterType(type), level); // DEBUG - RemoveMe - if (configTimeStampFlag && ConfigMgr::GetBoolDefault(configTimeStampFlag, false)) + std::istringstream ss(GetConfigStringDefault(base, "Appenders", "")); + std::string str; + + ss >> str; + while (ss) { - size_t dot_pos = logfn.find_last_of("."); - if (dot_pos!=logfn.npos) - logfn.insert(dot_pos, m_logsTimestamp); + if (Appender* appender = GetAppenderByName(str)) + { + logger.addAppender(appender->getId(), appender); + //fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name); // DEBUG - RemoveMe + } else - logfn += m_logsTimestamp; + fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist", str.c_str(), name); + ss >> str; } - - return fopen((m_logsDir+logfn).c_str(), mode); } -FILE* Log::openGmlogPerAccount(uint32 account) +void Log::ReadAppendersFromConfig() { - if (m_gmlog_filename_format.empty()) - return NULL; + std::istringstream ss(ConfigMgr::GetStringDefault("Appenders", "")); + std::string name; - char namebuf[TRINITY_PATH_MAX]; - snprintf(namebuf, TRINITY_PATH_MAX, m_gmlog_filename_format.c_str(), account); - return fopen(namebuf, "a"); + do + { + ss >> name; + CreateAppenderFromConfig(name.c_str()); + name = ""; + } + while (ss); } -void Log::outTimestamp(FILE* file) +void Log::ReadLoggersFromConfig() { - time_t t = time(NULL); - tm* aTm = localtime(&t); - // YYYY year - // MM month (2 digits 01-12) - // DD day (2 digits 01-31) - // HH hour (2 digits 00-23) - // MM minutes (2 digits 00-59) - // SS seconds (2 digits 00-59) - fprintf(file, "%-4d-%02d-%02d %02d:%02d:%02d ", aTm->tm_year+1900, aTm->tm_mon+1, aTm->tm_mday, aTm->tm_hour, aTm->tm_min, aTm->tm_sec); -} + std::istringstream ss(ConfigMgr::GetStringDefault("Loggers", "")); + std::string name; -void Log::InitColors(const std::string& str) -{ - if (str.empty()) + do { - m_colored = false; - return; + ss >> name; + CreateLoggerFromConfig(name.c_str()); + name = ""; } + while (ss); - int color[4]; - - std::istringstream ss(str); + LoggerMap::const_iterator it = loggers.begin(); - for (uint8 i = 0; i < LogLevels; ++i) - { - ss >> color[i]; + while (it != loggers.end() && it->first) + ++it; - if (!ss) - return; - - if (color[i] < 0 || color[i] >= Colors) - return; - } + // root logger must exist. Marking as disabled as its not configured + if (it == loggers.end()) + loggers[0].Create("root", LOG_FILTER_GENERAL, LOG_LEVEL_DISABLED); +} - for (uint8 i = 0; i < LogLevels; ++i) - m_colors[i] = ColorTypes(color[i]); +void Log::EnableDBAppenders() +{ + for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) + if (it->second && it->second->getType() == APPENDER_DB) + ((AppenderDB *)it->second)->setEnable(true); - m_colored = true; } -void Log::SetColor(bool stdout_stream, ColorTypes color) +void Log::log(LogFilterType filter, LogLevel level, char const* str, ...) { - #if PLATFORM == PLATFORM_WINDOWS - static WORD WinColorFG[Colors] = - { - 0, // BLACK - FOREGROUND_RED, // RED - FOREGROUND_GREEN, // GREEN - FOREGROUND_RED | FOREGROUND_GREEN, // BROWN - FOREGROUND_BLUE, // BLUE - FOREGROUND_RED | FOREGROUND_BLUE, // MAGENTA - FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN - FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // WHITE - // YELLOW - FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, - // RED_BOLD - FOREGROUND_RED | FOREGROUND_INTENSITY, - // GREEN_BOLD - FOREGROUND_GREEN | FOREGROUND_INTENSITY, - FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD - // MAGENTA_BOLD - FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, - // CYAN_BOLD - FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, - // WHITE_BOLD - FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY - }; - - HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE ); - SetConsoleTextAttribute(hConsole, WinColorFG[color]); - #else - enum ANSITextAttr - { - TA_NORMAL=0, - TA_BOLD=1, - TA_BLINK=5, - TA_REVERSE=7 - }; + if (!str || !ShouldLog(filter, level)) + return; - enum ANSIFgTextAttr - { - FG_BLACK=30, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, - FG_MAGENTA, FG_CYAN, FG_WHITE, FG_YELLOW - }; + va_list ap; + va_start(ap, str); - enum ANSIBgTextAttr - { - BG_BLACK=40, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, - BG_MAGENTA, BG_CYAN, BG_WHITE - }; + vlog(filter, level, str, ap); - static uint8 UnixColorFG[Colors] = - { - FG_BLACK, // BLACK - FG_RED, // RED - FG_GREEN, // GREEN - FG_BROWN, // BROWN - FG_BLUE, // BLUE - FG_MAGENTA, // MAGENTA - FG_CYAN, // CYAN - FG_WHITE, // WHITE - FG_YELLOW, // YELLOW - FG_RED, // LRED - FG_GREEN, // LGREEN - FG_BLUE, // LBLUE - FG_MAGENTA, // LMAGENTA - FG_CYAN, // LCYAN - FG_WHITE // LWHITE - }; - - fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < Colors ? ";1" : "")); - #endif + va_end(ap); +} + +void Log::vlog(LogFilterType filter, LogLevel level, char const* str, va_list argptr) +{ + char text[MAX_QUERY_LEN]; + vsnprintf(text, MAX_QUERY_LEN, str, argptr); + write(new LogMessage(level, filter, text)); } -void Log::ResetColor(bool stdout_stream) +void Log::write(LogMessage* msg) { - #if PLATFORM == PLATFORM_WINDOWS - HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE ); - SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ); - #else - fprintf(( stdout_stream ? stdout : stderr ), "\x1b[0m"); - #endif + msg->text.append("\n"); + Logger* logger = GetLoggerByType(msg->type); + worker->enqueue(new LogOperation(logger, msg)); } std::string Log::GetTimestampStr() @@ -370,710 +273,160 @@ std::string Log::GetTimestampStr() return std::string(buf); } -void Log::outDB(LogTypes type, const char * str) +bool Log::SetLogLevel(std::string const& name, const char* newLevelc, bool isLogger /* = true */) { - if (!str || type >= MAX_LOG_TYPES) - return; + LogLevel newLevel = LogLevel(atoi(newLevelc)); + if (newLevel < 0) + return false; - std::string logStr(str); - if (logStr.empty()) - return; - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG); - - stmt->setInt32(0, realm); - stmt->setUInt8(1, uint8(type)); - stmt->setString(2, logStr); - - LoginDatabase.Execute(stmt); -} - -void Log::outString(const char * str, ...) -{ - if (!str) - return; - - if (m_enableLogDB) + if (isLogger) { - // we don't want empty strings in the DB - std::string s(str); - if (s.empty() || s == " ") - return; - - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_STRING, nnew_str); - va_end(ap2); - } + LoggerMap::iterator it = loggers.begin(); + while (it != loggers.end() && it->second.getName() != name) + ++it; - if (m_colored) - SetColor(true, m_colors[LOGL_NORMAL]); + if (it == loggers.end()) + return false; - va_list ap; - - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - - if (m_colored) - ResetColor(true); - - printf("\n"); - if (logfile) - { - outTimestamp(logfile); - va_start(ap, str); - vfprintf(logfile, str, ap); - fprintf(logfile, "\n"); - va_end(ap); - - fflush(logfile); + it->second.setLogLevel(newLevel); } - fflush(stdout); -} - -void Log::outString() -{ - printf("\n"); - if (logfile) - { - outTimestamp(logfile); - fprintf(logfile, "\n"); - fflush(logfile); - } - fflush(stdout); -} - -void Log::outCrash(const char * err, ...) -{ - if (!err) - return; - - if (m_enableLogDB) - { - va_list ap2; - va_start(ap2, err); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, err, ap2); - outDB(LOG_TYPE_CRASH, nnew_str); - va_end(ap2); - } - - if (m_colored) - SetColor(false, LRED); - - va_list ap; - - va_start(ap, err); - vutf8printf(stderr, err, &ap); - va_end(ap); - - if (m_colored) - ResetColor(false); - - fprintf(stderr, "\n"); - if (logfile) + else { - outTimestamp(logfile); - fprintf(logfile, "CRASH ALERT: "); - - va_start(ap, err); - vfprintf(logfile, err, ap); - va_end(ap); + Appender* appender = GetAppenderByName(name); + if (!appender) + return false; - fprintf(logfile, "\n"); - fflush(logfile); + appender->setLogLevel(newLevel); } - fflush(stderr); + return true; } -void Log::outError(const char * err, ...) +bool Log::ShouldLog(LogFilterType type, LogLevel level) const { - if (!err) - return; - - if (m_enableLogDB) - { - va_list ap2; - va_start(ap2, err); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, err, ap2); - outDB(LOG_TYPE_ERROR, nnew_str); - va_end(ap2); - } - - if (m_colored) - SetColor(false, LRED); - - va_list ap; - - va_start(ap, err); - vutf8printf(stderr, err, &ap); - va_end(ap); + LoggerMap::const_iterator it = loggers.begin(); + while (it != loggers.end() && it->second.getType() != type) + ++it; - if (m_colored) - ResetColor(false); - - fprintf( stderr, "\n"); - if (logfile) + if (it != loggers.end()) { - outTimestamp(logfile); - fprintf(logfile, "ERROR: "); - - va_start(ap, err); - vfprintf(logfile, err, ap); - va_end(ap); - - fprintf(logfile, "\n"); - fflush(logfile); + LogLevel loggerLevel = it->second.getLogLevel(); + return loggerLevel && loggerLevel <= level; } - fflush(stderr); -} -void Log::outArena(const char * str, ...) -{ - if (!str) - return; + if (type != LOG_FILTER_GENERAL) + return ShouldLog(LOG_FILTER_GENERAL, level); - if (arenaLogFile) - { - va_list ap; - outTimestamp(arenaLogFile); - va_start(ap, str); - vfprintf(arenaLogFile, str, ap); - fprintf(arenaLogFile, "\n"); - va_end(ap); - fflush(arenaLogFile); - } + return false; } -void Log::outSQLDriver(const char* str, ...) +void Log::outTrace(LogFilterType filter, const char * str, ...) { - if (!str) + if (!str || !ShouldLog(filter, LOG_LEVEL_TRACE)) return; va_list ap; va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - - printf("\n"); - - if (sqlLogFile) - { - outTimestamp(sqlLogFile); - - va_list apSQL; - va_start(apSQL, str); - vfprintf(sqlLogFile, str, apSQL); - va_end(apSQL); - - fprintf(sqlLogFile, "\n"); - fflush(sqlLogFile); - } - - fflush(stdout); -} - -void Log::outErrorDb(const char * err, ...) -{ - if (!err) - return; - - if (m_colored) - SetColor(false, LRED); - va_list ap; + vlog(filter, LOG_LEVEL_TRACE, str, ap); - va_start(ap, err); - vutf8printf(stderr, err, &ap); va_end(ap); - - if (m_colored) - ResetColor(false); - - fprintf( stderr, "\n" ); - - if (logfile) - { - outTimestamp(logfile); - fprintf(logfile, "ERROR: " ); - - va_start(ap, err); - vfprintf(logfile, err, ap); - va_end(ap); - - fprintf(logfile, "\n" ); - fflush(logfile); - } - - if (dberLogfile) - { - outTimestamp(dberLogfile); - va_start(ap, err); - vfprintf(dberLogfile, err, ap); - va_end(ap); - - fprintf(dberLogfile, "\n" ); - fflush(dberLogfile); - } - fflush(stderr); } -void Log::outBasic(const char * str, ...) +void Log::outDebug(LogFilterType filter, const char * str, ...) { - if (!str) + if (!str || !ShouldLog(filter, LOG_LEVEL_DEBUG)) return; - if (m_enableLogDB && m_dbLogLevel > LOGL_NORMAL) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_BASIC, nnew_str); - va_end(ap2); - } - - if (m_logLevel > LOGL_NORMAL) - { - if (m_colored) - SetColor(true, m_colors[LOGL_BASIC]); - - va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - - if (m_colored) - ResetColor(true); - - printf("\n"); - - if (logfile) - { - outTimestamp(logfile); - va_list ap2; - va_start(ap2, str); - vfprintf(logfile, str, ap2); - fprintf(logfile, "\n" ); - va_end(ap2); - fflush(logfile); - } - } - fflush(stdout); -} - -void Log::outDetail(const char * str, ...) -{ - if (!str) - return; - - if (m_enableLogDB && m_dbLogLevel > LOGL_BASIC) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_DETAIL, nnew_str); - va_end(ap2); - } - - if (m_logLevel > LOGL_BASIC) - { - if (m_colored) - SetColor(true, m_colors[LOGL_DETAIL]); - - va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - - if (m_colored) - ResetColor(true); + va_list ap; + va_start(ap, str); - printf("\n"); + vlog(filter, LOG_LEVEL_DEBUG, str, ap); - if (logfile) - { - outTimestamp(logfile); - va_list ap2; - va_start(ap2, str); - vfprintf(logfile, str, ap2); - va_end(ap2); - - fprintf(logfile, "\n"); - fflush(logfile); - } - } - - fflush(stdout); + va_end(ap); } -void Log::outDebugInLine(const char * str, ...) +void Log::outInfo(LogFilterType filter, const char * str, ...) { - if (!str) + if (!str || !ShouldLog(filter, LOG_LEVEL_INFO)) return; - if (m_logLevel > LOGL_DETAIL) - { - va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); + va_list ap; + va_start(ap, str); - //if (m_colored) - // ResetColor(true); + vlog(filter, LOG_LEVEL_INFO, str, ap); - if (logfile) - { - va_list ap2; - va_start(ap2, str); - vfprintf(logfile, str, ap2); - va_end(ap2); - } - } + va_end(ap); } -void Log::outSQLDev(const char* str, ...) +void Log::outWarn(LogFilterType filter, const char * str, ...) { - if (!str) + if (!str || !ShouldLog(filter, LOG_LEVEL_WARN)) return; va_list ap; va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - printf("\n"); + vlog(filter, LOG_LEVEL_WARN, str, ap); - if (sqlDevLogFile) - { - va_list ap2; - va_start(ap2, str); - vfprintf(sqlDevLogFile, str, ap2); - va_end(ap2); - - fprintf(sqlDevLogFile, "\n"); - fflush(sqlDevLogFile); - } - - fflush(stdout); + va_end(ap); } -void Log::outDebug(DebugLogFilters f, const char * str, ...) +void Log::outError(LogFilterType filter, const char * str, ...) { - if (!(m_DebugLogMask & f)) - return; - - if (!str) + if (!str || !ShouldLog(filter, LOG_LEVEL_ERROR)) return; - if (m_enableLogDB && m_dbLogLevel > LOGL_DETAIL) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_DEBUG, nnew_str); - va_end(ap2); - } - - if ( m_logLevel > LOGL_DETAIL ) - { - if (m_colored) - SetColor(true, m_colors[LOGL_DEBUG]); - - va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - - if (m_colored) - ResetColor(true); + va_list ap; + va_start(ap, str); - printf( "\n" ); + vlog(filter, LOG_LEVEL_ERROR, str, ap); - if (logfile) - { - outTimestamp(logfile); - va_list ap2; - va_start(ap2, str); - vfprintf(logfile, str, ap2); - va_end(ap2); - - fprintf(logfile, "\n" ); - fflush(logfile); - } - } - fflush(stdout); + va_end(ap); } -void Log::outStaticDebug(const char * str, ...) +void Log::outFatal(LogFilterType filter, const char * str, ...) { - if (!str) + if (!str || !ShouldLog(filter, LOG_LEVEL_FATAL)) return; - if (m_enableLogDB && m_dbLogLevel > LOGL_DETAIL) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_DEBUG, nnew_str); - va_end(ap2); - } - - if ( m_logLevel > LOGL_DETAIL ) - { - if (m_colored) - SetColor(true, m_colors[LOGL_DEBUG]); - - va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); - - if (m_colored) - ResetColor(true); + va_list ap; + va_start(ap, str); - printf( "\n" ); + vlog(filter, LOG_LEVEL_FATAL, str, ap); - if (logfile) - { - outTimestamp(logfile); - va_list ap2; - va_start(ap2, str); - vfprintf(logfile, str, ap2); - va_end(ap2); - - fprintf(logfile, "\n" ); - fflush(logfile); - } - } - fflush(stdout); + va_end(ap); } -void Log::outStringInLine(const char * str, ...) +void Log::outCommand(uint32 account, const char * str, ...) { - if (!str) + if (!str || !ShouldLog(LOG_FILTER_GMCOMMAND, LOG_LEVEL_INFO)) return; va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); + char text[MAX_QUERY_LEN]; + vsnprintf(text, MAX_QUERY_LEN, str, ap); va_end(ap); - if (logfile) - { - va_start(ap, str); - vfprintf(logfile, str, ap); - va_end(ap); - } -} - -void Log::outCommand(uint32 account, const char * str, ...) -{ - if (!str) - return; - - // TODO: support accountid - if (m_enableLogDB && m_dbGM) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_GM, nnew_str); - va_end(ap2); - } - - if (m_logLevel > LOGL_NORMAL) - { - if (m_colored) - SetColor(true, m_colors[LOGL_BASIC]); - - va_list ap; - va_start(ap, str); - vutf8printf(stdout, str, &ap); - va_end(ap); + LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, LOG_FILTER_GMCOMMAND, text); + msg->param1 = account; - if (m_colored) - ResetColor(true); - - printf("\n"); - - if (logfile) - { - outTimestamp(logfile); - va_list ap2; - va_start(ap2, str); - vfprintf(logfile, str, ap2); - fprintf(logfile, "\n" ); - va_end(ap2); - fflush(logfile); - } - } - - if (m_gmlog_per_account) - { - if (FILE* per_file = openGmlogPerAccount (account)) - { - outTimestamp(per_file); - va_list ap; - va_start(ap, str); - vfprintf(per_file, str, ap); - fprintf(per_file, "\n" ); - va_end(ap); - fclose(per_file); - } - } - else if (gmLogfile) - { - outTimestamp(gmLogfile); - va_list ap; - va_start(ap, str); - vfprintf(gmLogfile, str, ap); - fprintf(gmLogfile, "\n" ); - va_end(ap); - fflush(gmLogfile); - } - - fflush(stdout); + write(msg); } -void Log::outChar(const char * str, ...) +void Log::SetRealmID(uint32 id) { - if (!str) - return; - - if (m_enableLogDB && m_dbChar) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_CHAR, nnew_str); - va_end(ap2); - } - - if (charLogfile) - { - outTimestamp(charLogfile); - va_list ap; - va_start(ap, str); - vfprintf(charLogfile, str, ap); - fprintf(charLogfile, "\n" ); - va_end(ap); - fflush(charLogfile); - } -} - -void Log::outCharDump(const char * str, uint32 account_id, uint32 guid, const char * name) -{ - FILE* file = NULL; - if (m_charLog_Dump_Separate) - { - char fileName[29]; // Max length: name(12) + guid(11) + _.log (5) + \0 - snprintf(fileName, 29, "%d_%s.log", guid, name); - std::string sFileName(m_dumpsDir); - sFileName.append(fileName); - file = fopen((m_logsDir + sFileName).c_str(), "w"); - } - else - file = charLogfile; - if (file) - { - fprintf(file, "== START DUMP == (account: %u guid: %u name: %s )\n%s\n== END DUMP ==\n", - account_id, guid, name, str); - fflush(file); - if (m_charLog_Dump_Separate) - fclose(file); - } -} - -void Log::outRemote(const char * str, ...) -{ - if (!str) - return; - - if (m_enableLogDB && m_dbRA) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_RA, nnew_str); - va_end(ap2); - } - - if (raLogfile) - { - outTimestamp(raLogfile); - va_list ap; - va_start(ap, str); - vfprintf(raLogfile, str, ap); - fprintf(raLogfile, "\n" ); - va_end(ap); - fflush(raLogfile); - } + realm = id; } -void Log::outChat(const char * str, ...) +void Log::Close() { - if (!str) - return; - - if (m_enableLogDB && m_dbChat) - { - va_list ap2; - va_start(ap2, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); - outDB(LOG_TYPE_CHAT, nnew_str); - va_end(ap2); - } - - if (chatLogfile) - { - outTimestamp(chatLogfile); - va_list ap; - va_start(ap, str); - vfprintf(chatLogfile, str, ap); - fprintf(chatLogfile, "\n" ); - fflush(chatLogfile); - va_end(ap); - } -} - -void Log::outErrorST(const char * str, ...) -{ - va_list ap; - va_start(ap, str); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap); - va_end(ap); - - ACE_Stack_Trace st; - outError("%s [Stacktrace: %s]", nnew_str, st.c_str()); -} - -void Log::outWarden(const char * str, ...) -{ - if (!str) - return; - - if (wardenLogFile) + for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) { - outTimestamp(wardenLogFile); - va_list ap; - va_start(ap, str); - vfprintf(wardenLogFile, str, ap); - fprintf(wardenLogFile, "\n" ); - fflush(wardenLogFile); - va_end(ap); + delete it->second; + it->second = NULL; } + appenders.clear(); + delete worker; + worker = NULL; } diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index 296c13d86c9..5e2b7972dc8 100755 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -19,196 +19,69 @@ #ifndef TRINITYCORE_LOG_H #define TRINITYCORE_LOG_H -#include "Common.h" -#include <ace/Singleton.h> - -class Config; +#include "Define.h" +#include "Appender.h" +#include "LogWorker.h" +#include "Logger.h" -enum DebugLogFilters -{ - LOG_FILTER_NONE = 0x00000000, - LOG_FILTER_UNITS = 0x00000001, // Anything related to units that doesn't fit in other categories. ie. creature formations - LOG_FILTER_PETS = 0x00000002, - LOG_FILTER_VEHICLES = 0x00000004, - LOG_FILTER_TSCR = 0x00000008, // C++ AI, instance scripts, etc. - LOG_FILTER_DATABASE_AI = 0x00000010, // SmartAI, EventAI, CreatureAI - LOG_FILTER_MAPSCRIPTS = 0x00000020, - LOG_FILTER_NETWORKIO = 0x00000040, // Anything packet/netcode related - LOG_FILTER_SPELLS_AURAS = 0x00000080, - LOG_FILTER_ACHIEVEMENTSYS = 0x00000100, - LOG_FILTER_CONDITIONSYS = 0x00000200, - LOG_FILTER_POOLSYS = 0x00000400, - LOG_FILTER_AUCTIONHOUSE = 0x00000800, - LOG_FILTER_BATTLEGROUND = 0x00001000, // Anything related to arena's and battlegrounds - LOG_FILTER_OUTDOORPVP = 0x00002000, - LOG_FILTER_CHATSYS = 0x00004000, - LOG_FILTER_LFG = 0x00008000, - LOG_FILTER_MAPS = 0x00010000, // Maps, instances, grids, cells, visibility - LOG_FILTER_PLAYER_LOADING = 0x00020000, // Debug output from Player::_Load functions - LOG_FILTER_PLAYER_ITEMS = 0x00040000, // Anything item related - LOG_FILTER_PLAYER_SKILLS = 0x00080000, // Skills related - LOG_FILTER_LOOT = 0x00100000, // Loot related - LOG_FILTER_GUILD = 0x00200000, // Guild related - LOG_FILTER_TRANSPORTS = 0x00400000, // Transport related - LOG_FILTER_WARDEN = 0x00800000, // Warden related -}; - -enum LogTypes -{ - LOG_TYPE_STRING = 0, - LOG_TYPE_ERROR = 1, - LOG_TYPE_BASIC = 2, - LOG_TYPE_DETAIL = 3, - LOG_TYPE_DEBUG = 4, - LOG_TYPE_CHAR = 5, - LOG_TYPE_WORLD = 6, - LOG_TYPE_RA = 7, - LOG_TYPE_GM = 8, - LOG_TYPE_CRASH = 9, - LOG_TYPE_CHAT = 10, - MAX_LOG_TYPES -}; - -enum LogLevel -{ - LOGL_NORMAL = 0, - LOGL_BASIC, - LOGL_DETAIL, - LOGL_DEBUG -}; - -const int LogLevels = int(LOGL_DEBUG)+1; - -enum ColorTypes -{ - BLACK, - RED, - GREEN, - BROWN, - BLUE, - MAGENTA, - CYAN, - GREY, - YELLOW, - LRED, - LGREEN, - LBLUE, - LMAGENTA, - LCYAN, - WHITE -}; +#include <ace/Singleton.h> -const int Colors = int(WHITE)+1; +#include <string> +#include <set> class Log { friend class ACE_Singleton<Log, ACE_Thread_Mutex>; + typedef std::map<uint8, Logger> LoggerMap; + private: Log(); ~Log(); public: - void Initialize(); - - void ReloadConfig(); - - void InitColors(const std::string& init_str); - void SetColor(bool stdout_stream, ColorTypes color); - void ResetColor(bool stdout_stream); - - void outErrorST(const char * err, ...) ATTR_PRINTF(2, 3); - void outDB(LogTypes type, const char * str); - void outString(const char * str, ...) ATTR_PRINTF(2, 3); - void outString(); - void outStringInLine(const char * str, ...) ATTR_PRINTF(2, 3); - void outError(const char * err, ...) ATTR_PRINTF(2, 3); - void outCrash(const char * err, ...) ATTR_PRINTF(2, 3); - void outBasic(const char * str, ...) ATTR_PRINTF(2, 3); - void outDetail(const char * str, ...) ATTR_PRINTF(2, 3); - void outSQLDev(const char * str, ...) ATTR_PRINTF(2, 3); - void outDebug(DebugLogFilters f, const char* str, ...) ATTR_PRINTF(3, 4); - void outStaticDebug(const char * str, ...) ATTR_PRINTF(2, 3); - void outDebugInLine(const char * str, ...) ATTR_PRINTF(2, 3); - void outErrorDb(const char * str, ...) ATTR_PRINTF(2, 3); - void outChar(const char * str, ...) ATTR_PRINTF(2, 3); - void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4); - void outRemote(const char * str, ...) ATTR_PRINTF(2, 3); - void outChat(const char * str, ...) ATTR_PRINTF(2, 3); - void outArena(const char * str, ...) ATTR_PRINTF(2, 3); - void outSQLDriver(const char* str, ...) ATTR_PRINTF(2, 3); - void outWarden(const char * str, ...) ATTR_PRINTF(2, 3); - void outCharDump(const char * str, uint32 account_id, uint32 guid, const char * name); - - static void outTimestamp(FILE* file); - static std::string GetTimestampStr(); + void Close(); + bool ShouldLog(LogFilterType type, LogLevel level) const; + bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true); - void SetLogLevel(char * Level); - void SetLogFileLevel(char * Level); - void SetDBLogLevel(char * Level); - void SetSQLDriverQueryLogging(bool newStatus) { m_sqlDriverQueryLogging = newStatus; } - void SetRealmID(uint32 id) { realm = id; } + void log(LogFilterType f, LogLevel level, char const* str, ...) ATTR_PRINTF(4,5); + + void outTrace(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); + void outDebug(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); + void outInfo(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); + void outWarn(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); + void outError(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); + void outFatal(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); + + void EnableDBAppenders(); + void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4); + static std::string GetTimestampStr(); - bool IsOutDebug() const { return m_logLevel > 2 || (m_logFileLevel > 2 && logfile); } - bool IsOutCharDump() const { return m_charLog_Dump; } + void SetRealmID(uint32 id); - bool GetLogDB() const { return m_enableLogDB; } - bool GetLogDBLater() const { return m_enableLogDBLater; } - void SetLogDB(bool enable) { m_enableLogDB = enable; } - void SetLogDBLater(bool value) { m_enableLogDBLater = value; } - bool GetSQLDriverQueryLogging() const { return m_sqlDriverQueryLogging; } private: - FILE* openLogFile(char const* configFileName, char const* configTimeStampFlag, char const* mode); - FILE* openGmlogPerAccount(uint32 account); - - FILE* raLogfile; - FILE* logfile; - FILE* gmLogfile; - FILE* charLogfile; - FILE* dberLogfile; - FILE* chatLogfile; - FILE* arenaLogFile; - FILE* sqlLogFile; - FILE* sqlDevLogFile; - FILE* wardenLogFile; - - // cache values for after initilization use (like gm log per account case) + void vlog(LogFilterType f, LogLevel level, char const* str, va_list argptr); + void write(LogMessage* msg); + + Logger* GetLoggerByType(LogFilterType filter); + Appender* GetAppenderByName(std::string const& name); + uint8 NextAppenderId(); + void CreateAppenderFromConfig(const char* name); + void CreateLoggerFromConfig(const char* name); + void ReadAppendersFromConfig(); + void ReadLoggersFromConfig(); + + AppenderMap appenders; + LoggerMap loggers; + uint8 AppenderId; + std::string m_logsDir; std::string m_logsTimestamp; - // gm log control - bool m_gmlog_per_account; - std::string m_gmlog_filename_format; - - bool m_enableLogDBLater; - bool m_enableLogDB; uint32 realm; - - // log coloring - bool m_colored; - ColorTypes m_colors[4]; - - // log levels: - // false: errors only, true: full query logging - bool m_sqlDriverQueryLogging; - - // log levels: - // 0 minimum/string, 1 basic/error, 2 detail, 3 full/debug - uint8 m_dbLogLevel; - uint8 m_logLevel; - uint8 m_logFileLevel; - bool m_dbChar; - bool m_dbRA; - bool m_dbGM; - bool m_dbChat; - bool m_charLog_Dump; - bool m_charLog_Dump_Separate; - std::string m_dumpsDir; - - DebugLogFilters m_DebugLogMask; + LogWorker* worker; }; #define sLog ACE_Singleton<Log, ACE_Thread_Mutex>::instance() #endif - diff --git a/src/server/shared/Logging/LogOperation.cpp b/src/server/shared/Logging/LogOperation.cpp new file mode 100644 index 00000000000..59368e519cd --- /dev/null +++ b/src/server/shared/Logging/LogOperation.cpp @@ -0,0 +1,14 @@ +#include "LogOperation.h" +#include "Logger.h" + +LogOperation::~LogOperation() +{ + delete msg; +} + +int LogOperation::call() +{ + if (logger && msg) + logger->write(*msg); + return 0; +} diff --git a/src/server/shared/Logging/LogOperation.h b/src/server/shared/Logging/LogOperation.h new file mode 100644 index 00000000000..046ff44e62e --- /dev/null +++ b/src/server/shared/Logging/LogOperation.h @@ -0,0 +1,24 @@ +#ifndef LOGOPERATION_H +#define LOGOPERATION_H + +class Logger; +struct LogMessage; + +class LogOperation +{ + public: + LogOperation(Logger* _logger, LogMessage* _msg) + : logger(_logger) + , msg(_msg) + { } + + ~LogOperation(); + + int call(); + + protected: + Logger *logger; + LogMessage *msg; +}; + +#endif diff --git a/src/server/shared/Logging/LogWorker.cpp b/src/server/shared/Logging/LogWorker.cpp new file mode 100644 index 00000000000..4dc71f7f878 --- /dev/null +++ b/src/server/shared/Logging/LogWorker.cpp @@ -0,0 +1,33 @@ +#include "LogWorker.h" + +LogWorker::LogWorker() + : m_queue(HIGH_WATERMARK, LOW_WATERMARK) +{ + ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, 1); +} + +LogWorker::~LogWorker() +{ + m_queue.deactivate(); + wait(); +} + +int LogWorker::enqueue(LogOperation* op) +{ + return m_queue.enqueue(op); +} + +int LogWorker::svc() +{ + while (1) + { + LogOperation* request; + if (m_queue.dequeue(request) == -1) + break; + + request->call(); + delete request; + } + + return 0; +} diff --git a/src/server/shared/Logging/LogWorker.h b/src/server/shared/Logging/LogWorker.h new file mode 100644 index 00000000000..fe51be5376c --- /dev/null +++ b/src/server/shared/Logging/LogWorker.h @@ -0,0 +1,30 @@ +#ifndef LOGWORKER_H +#define LOGWORKER_H + +#include "LogOperation.h" + +#include <ace/Task.h> +#include <ace/Activation_Queue.h> + +class LogWorker: protected ACE_Task_Base +{ + public: + LogWorker(); + ~LogWorker(); + + typedef ACE_Message_Queue_Ex<LogOperation, ACE_MT_SYNCH> LogMessageQueueType; + + enum + { + HIGH_WATERMARK = 8 * 1024 * 1024, + LOW_WATERMARK = 8 * 1024 * 1024 + }; + + int enqueue(LogOperation *op); + + private: + virtual int svc(); + LogMessageQueueType m_queue; +}; + +#endif diff --git a/src/server/shared/Logging/Logger.cpp b/src/server/shared/Logging/Logger.cpp new file mode 100644 index 00000000000..7464012c0ac --- /dev/null +++ b/src/server/shared/Logging/Logger.cpp @@ -0,0 +1,67 @@ +#include "Logger.h" + +Logger::Logger(): name(""), type(LOG_FILTER_GENERAL), level(LOG_LEVEL_DISABLED) +{ +} + +void Logger::Create(std::string const& _name, LogFilterType _type, LogLevel _level) +{ + name = _name; + type = _type; + level = _level; +} + +Logger::~Logger() +{ + for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) + it->second = NULL; + appenders.clear(); +} + +std::string const& Logger::getName() const +{ + return name; +} + +LogFilterType Logger::getType() const +{ + return type; +} + +LogLevel Logger::getLogLevel() const +{ + return level; +} + +void Logger::addAppender(uint8 id, Appender* appender) +{ + appenders[id] = appender; +} + +void Logger::delAppender(uint8 id) +{ + AppenderMap::iterator it = appenders.find(id); + if (it != appenders.end()) + { + it->second = NULL; + appenders.erase(it); + } +} + +void Logger::setLogLevel(LogLevel _level) +{ + level = _level; +} + +void Logger::write(LogMessage& message) +{ + if (!level || level > message.level || message.text.empty()) + { + //fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), messge.level, message.text.c_str(), .message.level); // DEBUG - RemoveMe + return; + } + + for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) + if (it->second) + it->second->write(message); +} diff --git a/src/server/shared/Logging/Logger.h b/src/server/shared/Logging/Logger.h new file mode 100644 index 00000000000..10b3991a537 --- /dev/null +++ b/src/server/shared/Logging/Logger.h @@ -0,0 +1,29 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include "Appender.h" + +class Logger +{ + public: + Logger(); + ~Logger(); + + void Create(std::string const& name, LogFilterType type, LogLevel level); + void addAppender(uint8 type, Appender *); + void delAppender(uint8 type); + + std::string const& getName() const; + LogFilterType getType() const; + LogLevel getLogLevel() const; + void setLogLevel(LogLevel level); + void write(LogMessage& message); + + private: + std::string name; + LogFilterType type; + LogLevel level; + AppenderMap appenders; +}; + +#endif diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 4fac31a9ac6..6912e841bc3 100755 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -50,7 +50,7 @@ class ByteBufferPositionException : public ByteBufferException protected: void PrintError() const { - sLog->outError("Attempted to %s value with size: "SIZEFMTD" in ByteBuffer (pos: " SIZEFMTD " size: "SIZEFMTD") " , + sLog->outError(LOG_FILTER_GENERAL, "Attempted to %s value with size: "SIZEFMTD" in ByteBuffer (pos: " SIZEFMTD " size: "SIZEFMTD") " , (_add ? "put" : "get"), ValueSize, Pos, Size); } @@ -70,7 +70,7 @@ class ByteBufferSourceException : public ByteBufferException protected: void PrintError() const { - sLog->outError("Attempted to put a %s in ByteBuffer (pos: "SIZEFMTD" size: "SIZEFMTD")", + sLog->outError(LOG_FILTER_GENERAL, "Attempted to put a %s in ByteBuffer (pos: "SIZEFMTD" size: "SIZEFMTD")", (ValueSize > 0 ? "NULL-pointer" : "zero-sized value"), Pos, Size); } }; @@ -447,79 +447,65 @@ class ByteBuffer void print_storage() const { - if (!sLog->IsOutDebug()) // optimize disabled debug output + if (!sLog->ShouldLog(LOG_FILTER_NETWORKIO, LOG_LEVEL_TRACE)) // optimize disabled debug output return; - sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE_SIZE: %lu", (unsigned long)size() ); + std::ostringstream o; + o << "STORAGE_SIZE: " << size(); for (uint32 i = 0; i < size(); ++i) - sLog->outDebugInLine("%u - ", read<uint8>(i) ); - sLog->outDebug(LOG_FILTER_NETWORKIO, " "); + o << read<uint8>(i) << " - "; + o << " "; + + sLog->outTrace(LOG_FILTER_NETWORKIO, "%s", o.str().c_str()); } void textlike() const { - if (!sLog->IsOutDebug()) // optimize disabled debug output + if (!sLog->ShouldLog(LOG_FILTER_NETWORKIO, LOG_LEVEL_TRACE)) // optimize disabled debug output return; - sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE_SIZE: %lu", (unsigned long)size() ); + std::ostringstream o; + o << "STORAGE_SIZE: " << size(); for (uint32 i = 0; i < size(); ++i) - sLog->outDebugInLine("%c", read<uint8>(i) ); - sLog->outDebug(LOG_FILTER_NETWORKIO, " "); + { + char buf[1]; + snprintf(buf, 1, "%c", read<uint8>(i)); + o << buf; + } + o << " "; + sLog->outTrace(LOG_FILTER_NETWORKIO, "%s", o.str().c_str()); } void hexlike() const { - if (!sLog->IsOutDebug()) // optimize disabled debug output + if (!sLog->ShouldLog(LOG_FILTER_NETWORKIO, LOG_LEVEL_TRACE)) // optimize disabled debug output return; - + uint32 j = 1, k = 1; - sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE_SIZE: %lu", (unsigned long)size() ); - + + std::ostringstream o; + o << "STORAGE_SIZE: " << size(); + for (uint32 i = 0; i < size(); ++i) { + char buf[3]; + snprintf(buf, 1, "%2X ", read<uint8>(i)); if ((i == (j * 8)) && ((i != (k * 16)))) { - if (read<uint8>(i) < 0x10) - { - sLog->outDebugInLine("| 0%X ", read<uint8>(i) ); - } - else - { - sLog->outDebugInLine("| %X ", read<uint8>(i) ); - } + o << "| "; ++j; } else if (i == (k * 16)) { - if (read<uint8>(i) < 0x10) - { - sLog->outDebugInLine("\n"); - - sLog->outDebugInLine("0%X ", read<uint8>(i) ); - } - else - { - sLog->outDebugInLine("\n"); - - sLog->outDebugInLine("%X ", read<uint8>(i) ); - } - + o << "\n"; ++k; ++j; } - else - { - if (read<uint8>(i) < 0x10) - { - sLog->outDebugInLine("0%X ", read<uint8>(i) ); - } - else - { - sLog->outDebugInLine("%X ", read<uint8>(i) ); - } - } + + o << buf; } - sLog->outDebugInLine("\n"); + o << " "; + sLog->outTrace(LOG_FILTER_NETWORKIO, "%s", o.str().c_str()); } protected: diff --git a/src/server/shared/Utilities/ServiceWin32.cpp b/src/server/shared/Utilities/ServiceWin32.cpp index f2887a4d1bd..c6e9d385be3 100755 --- a/src/server/shared/Utilities/ServiceWin32.cpp +++ b/src/server/shared/Utilities/ServiceWin32.cpp @@ -257,7 +257,7 @@ bool WinServiceRun() if (!StartServiceCtrlDispatcher(serviceTable)) { - sLog->outError("StartService Failed. Error [%u]", ::GetLastError()); + sLog->outError(LOG_FILTER_GENERAL, "StartService Failed. Error [%u]", ::GetLastError()); return false; } return true; |
