sal/osl/all/log.cxx | 193 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 178 insertions(+), 15 deletions(-)
New commits: commit 9fae75c41dd507a00b4dbf1d978af3e2a3127626 Author: Jan Holesovsky <ke...@collabora.com> AuthorDate: Mon May 5 18:32:49 2014 +0200 Commit: Thorsten Behrens <thorsten.behr...@cib.de> CommitDate: Thu Aug 30 04:09:03 2018 +0200 sal: backport logging features This is: - sal logging: Flush after having written the output. - V804: Decreased performance - add an option to pipe log output to file - Allow to set log level/path in file - sal: don't reopen logfile on every log line - sal: log windows trace output to debugger console - Optionally include timestamp in the log - This code wouldn't otherwise build on 5.0.7@Linux - Fix crash when logging.ini does not exist - sal: flush log-to-file, remove extra linefeeds otherwise diff --git a/sal/osl/all/log.cxx b/sal/osl/all/log.cxx index 056d2a4cd437..c7ea7970c195 100644 --- a/sal/osl/all/log.cxx +++ b/sal/osl/all/log.cxx @@ -15,13 +15,17 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <ctime> #include <sstream> #include <stdio.h> #include <string.h> +#include <fstream> #include "osl/thread.hxx" +#include "osl/process.h" #include "rtl/string.h" +#include "rtl/ustring.hxx" #include "sal/detail/log.h" #include "sal/log.hxx" #include "sal/types.h" @@ -32,6 +36,7 @@ #include <android/log.h> #elif defined WNT #include <process.h> +#include <windows.h> #define OSL_DETAIL_GETPID _getpid() #else #include <unistd.h> @@ -80,16 +85,16 @@ char const * toString(sal_detail_LogLevel level) { // the process is running": #if defined ANDROID -char const * getEnvironmentVariable() { +char const * getLogLevel() { return std::getenv("SAL_LOG"); } #else -char const * getEnvironmentVariable_() { - char const * p1 = std::getenv("SAL_LOG"); - if (p1 == 0) { - return 0; +char const * getEnvironmentVariable_(const char* env) { + char const * p1 = std::getenv(env); + if (p1 == nullptr) { + return nullptr; } char const * p2 = strdup(p1); // leaked if (p2 == 0) { @@ -98,9 +103,146 @@ char const * getEnvironmentVariable_() { return p2; } -char const * getEnvironmentVariable() { - static char const * env = getEnvironmentVariable_(); - return env; +bool getValueFromLoggingIniFile(const char* key, char* value) { + rtl::OUString programDirectoryURL; + rtl::OUString programDirectoryPath; + osl_getProcessWorkingDir(&(programDirectoryURL.pData)); + osl_getSystemPathFromFileURL(programDirectoryURL.pData, &programDirectoryPath.pData); + rtl::OUString aLogFile(programDirectoryPath + "/" + "logging.ini"); + std::ifstream logFileStream(rtl::OUStringToOString( aLogFile, RTL_TEXTENCODING_ASCII_US).getStr()); + if (!logFileStream.good()) + return false; + + std::size_t n; + std::string aKey; + std::string aValue; + std::string sWantedKey(key); + std::string sLine; + while (std::getline(logFileStream, sLine)) { + if (sLine.find('#') == 0) + continue; + if ( ( n = sLine.find('=') ) != std::string::npos) { + aKey = sLine.substr(0, n); + if (aKey != sWantedKey) + continue; + aValue = sLine.substr(n+1, sLine.length()); + sprintf(value, "%s", aValue.c_str()); + return true; + } + } + return false; +} + +char const * getLogLevel() { + // First check the environment variable, then the setting in logging.ini + static char const * env = getEnvironmentVariable_("SAL_LOG"); + if (env != nullptr) + return env; + + static char logLevel[1024]; + if (getValueFromLoggingIniFile("LogLevel", logLevel)) { + return logLevel; + } + + return nullptr; +} + +char const * getLogFilePath() { + // First check the environment variable, then the setting in logging.ini + static char const * logFile = getEnvironmentVariable_("SAL_LOG_FILE"); + if (logFile != nullptr) + return logFile; + + static char logFilePath[1024]; + if (getValueFromLoggingIniFile("LogFilePath", logFilePath)) { + return logFilePath; + } + + return nullptr; +} + +std::ofstream * getLogFile() { + static char const * logFilePath = getLogFilePath(); + if (logFilePath == nullptr) + return nullptr; + + static std::ofstream file(logFilePath, std::ios::app | std::ios::out); + return &file; +} + +void maybeOutputTimestamp(std::ostringstream &s) { + char const * env = getLogLevel(); + if (env == nullptr) + return; + bool outputTimestamp = false; + bool outputRelativeTimer = false; + for (char const * p = env;;) { + switch (*p++) { + case '\0': + if (outputTimestamp) { + char ts[100]; + TimeValue systemTime; + osl_getSystemTime(&systemTime); + TimeValue localTime; + osl_getLocalTimeFromSystemTime(&systemTime, &localTime); + oslDateTime dateTime; + osl_getDateTimeFromTimeValue(&localTime, &dateTime); + struct tm tm; + tm.tm_sec = dateTime.Seconds; + tm.tm_min = dateTime.Minutes; + tm.tm_hour = dateTime.Hours; + tm.tm_mday = dateTime.Day; + tm.tm_mon = dateTime.Month - 1; + tm.tm_year = dateTime.Year - 1900; + strftime(ts, sizeof(ts), "%Y-%m-%d:%H:%M:%S", &tm); + char milliSecs[10]; + sprintf(milliSecs, "%03d", static_cast<int>(dateTime.NanoSeconds/1000000)); + s << ts << '.' << milliSecs << ':'; + } + if (outputRelativeTimer) { + static bool beenHere = false; + static TimeValue first; + if (!beenHere) { + osl_getSystemTime(&first); + beenHere = true; + } + TimeValue now; + osl_getSystemTime(&now); + int seconds = now.Seconds - first.Seconds; + int milliSeconds; + if (now.Nanosec < first.Nanosec) { + seconds--; + milliSeconds = 1000-(first.Nanosec-now.Nanosec)/1000000; + } + else + milliSeconds = (now.Nanosec-first.Nanosec)/1000000; + char relativeTimestamp[100]; + sprintf(relativeTimestamp, "%d.%03d", seconds, milliSeconds); + s << relativeTimestamp << ':'; + } + return; + case '+': + { + char const * p1 = p; + while (*p1 != '.' && *p1 != '+' && *p1 != '-' && *p1 != '\0') { + ++p1; + } + if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("TIMESTAMP"))) + outputTimestamp = true; + else if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("RELATIVETIMER"))) + outputRelativeTimer = true; + char const * p2 = p1; + while (*p2 != '+' && *p2 != '-' && *p2 != '\0') { + ++p2; + } + p = p2; + } + break; + default: + ; // nothing + } + } + return; } #endif @@ -109,8 +251,8 @@ bool report(sal_detail_LogLevel level, char const * area) { if (level == SAL_DETAIL_LOG_LEVEL_DEBUG) return true; assert(area != 0); - char const * env = getEnvironmentVariable(); - if (env == 0) { + static char const * env = getLogLevel(); + if (env == 0 || strcmp(env, "+TIMESTAMP") == 0) { env = "+WARN"; } std::size_t areaLen = std::strlen(area); @@ -147,6 +289,10 @@ bool report(sal_detail_LogLevel level, char const * area) { } else if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("WARN"))) { match = level == SAL_DETAIL_LOG_LEVEL_WARN; + } else if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("TIMESTAMP"))) + { + // handled later + match = false; } else { return true; // upon an illegal SAL_LOG value, everything is considered @@ -181,8 +327,9 @@ void log( std::ostringstream s; #if !defined ANDROID // On Android, the area will be used as the "tag," and log info already - // contains the PID + // contains timestamp and PID. if (!sal_use_syslog) { + maybeOutputTimestamp(s); s << toString(level) << ':'; } if (level != SAL_DETAIL_LOG_LEVEL_DEBUG) { @@ -194,11 +341,13 @@ void log( if (level == SAL_DETAIL_LOG_LEVEL_DEBUG) { s << ' '; } else { + const size_t nStrLen(std::strlen(SRCDIR "/")); s << (where - + (std::strncmp(where, SRCDIR "/", std::strlen(SRCDIR "/")) == 0 - ? std::strlen(SRCDIR "/") : 0)); + + (std::strncmp(where, SRCDIR "/", nStrLen) == 0 + ? nStrLen : 0)); } - s << message << '\n'; + s << message; + #if defined ANDROID int android_log_level; switch (level) { @@ -239,7 +388,21 @@ void log( syslog(prio, "%s", s.str().c_str()); #endif } else { - std::fputs(s.str().c_str(), stderr); + static std::ofstream * logFile = getLogFile(); + if (logFile) { + *logFile << s.str() << std::endl; + } +#if defined WNT + else { + OutputDebugString(s.str().c_str()); + } +#else + else { + s << '\n'; + std::fputs(s.str().c_str(), stderr); + std::fflush(stderr); + } +#endif } #endif } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits