|
29 | 29 |
|
30 | 30 | Implements logging functions. This file is based on the concepts from |
31 | 31 | SoftHSM v1 but extends the logging functions with support for a variable |
32 | | - argument list as defined in stdarg (3). |
| 32 | + argument list as defined in stdarg (3) and logging to file. |
33 | 33 | *****************************************************************************/ |
34 | 34 |
|
35 | 35 | #include "config.h" |
|
38 | 38 | #include <stdio.h> |
39 | 39 | #include <sstream> |
40 | 40 | #include <vector> |
| 41 | +#include <time.h> |
| 42 | +#ifdef _WIN32 |
| 43 | +#include <windows.h> |
| 44 | +#include <process.h> |
| 45 | +#else |
| 46 | +#include <unistd.h> |
| 47 | +#endif |
41 | 48 | #include "log.h" |
| 49 | +#include "MutexFactory.h" |
42 | 50 |
|
43 | 51 | int softLogLevel = LOG_DEBUG; |
| 52 | +static FILE* logFile = nullptr; |
| 53 | +static Mutex* logMutex = nullptr; |
44 | 54 |
|
45 | 55 | bool setLogLevel(const std::string &loglevel) |
46 | 56 | { |
@@ -69,6 +79,104 @@ bool setLogLevel(const std::string &loglevel) |
69 | 79 | return true; |
70 | 80 | } |
71 | 81 |
|
| 82 | +bool setLogFile(const std::string &logFilePath) |
| 83 | +{ |
| 84 | + // Quick return without creating mutex for default configuration |
| 85 | + if (logFilePath.empty() && logFile == nullptr) |
| 86 | + { |
| 87 | + return true; |
| 88 | + } |
| 89 | + |
| 90 | + if (logMutex == nullptr) |
| 91 | + { |
| 92 | + // Create mutex for later access |
| 93 | + logMutex = MutexFactory::i()->getMutex(); |
| 94 | + } |
| 95 | + |
| 96 | + if (logFile != nullptr) |
| 97 | + { |
| 98 | + fclose(logFile); |
| 99 | + logFile = nullptr; |
| 100 | + } |
| 101 | + |
| 102 | + if (logFilePath.empty()) |
| 103 | + { |
| 104 | + return true; |
| 105 | + } |
| 106 | + |
| 107 | + // This function needs to be called in init so it does not need locking |
| 108 | + logFile = fopen(logFilePath.c_str(), "a"); |
| 109 | + if (logFile == nullptr) |
| 110 | + { |
| 111 | + syslog(LOG_ERR, "Failed to open log file: %s, using syslog only", logFilePath.c_str()); |
| 112 | + return false; |
| 113 | + } |
| 114 | + |
| 115 | + return true; |
| 116 | +} |
| 117 | + |
| 118 | +void closeLogFile() |
| 119 | +{ |
| 120 | + if (logFile != nullptr) |
| 121 | + { |
| 122 | + fclose(logFile); |
| 123 | + logFile = nullptr; |
| 124 | + } |
| 125 | + |
| 126 | + if (logMutex != nullptr) |
| 127 | + { |
| 128 | + MutexFactory::i()->recycleMutex(logMutex); |
| 129 | + logMutex = nullptr; |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +static const char* getLevelString(int loglevel) |
| 134 | +{ |
| 135 | + switch(loglevel) |
| 136 | + { |
| 137 | + case LOG_ERR: return "ERROR"; |
| 138 | + case LOG_WARNING: return "WARNING"; |
| 139 | + case LOG_INFO: return "INFO"; |
| 140 | + case LOG_DEBUG: return "DEBUG"; |
| 141 | + default: return "UNKNOWN"; |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +static void writeLogToFile(const int loglevel, const char* prependText, const char* msgText) |
| 146 | +{ |
| 147 | + MutexLocker lock(logMutex); |
| 148 | + |
| 149 | +#ifdef _WIN32 |
| 150 | + SYSTEMTIME st; |
| 151 | + GetLocalTime(&st); |
| 152 | + fprintf(logFile, "%04d-%02d-%02d %02d:%02d:%02d.%03d [%d] %s: %s%s\n", |
| 153 | + st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, |
| 154 | + _getpid(), getLevelString(loglevel), prependText, msgText); |
| 155 | +#else |
| 156 | + char basetime[32]; |
| 157 | + long millis; |
| 158 | +#ifdef CLOCK_REALTIME |
| 159 | + struct timespec ts; |
| 160 | + clock_gettime(CLOCK_REALTIME, &ts); |
| 161 | + struct tm timeinfo; |
| 162 | + localtime_r(&ts.tv_sec, &timeinfo); |
| 163 | + millis = ts.tv_nsec / 1000000; |
| 164 | +#else |
| 165 | + struct timeval tv; |
| 166 | + gettimeofday(&tv, NULL); |
| 167 | + struct tm timeinfo; |
| 168 | + localtime_r(&tv.tv_sec, &timeinfo); |
| 169 | + millis = tv.tv_usec / 1000; |
| 170 | +#endif |
| 171 | + strftime(basetime, sizeof(basetime), "%Y-%m-%d %H:%M:%S", &timeinfo); |
| 172 | + fprintf(logFile, "%s.%03ld [%d] %s: %s%s\n", |
| 173 | + basetime, millis, |
| 174 | + (int)getpid(), getLevelString(loglevel), prependText, msgText); |
| 175 | +#endif |
| 176 | + |
| 177 | + fflush(logFile); |
| 178 | +} |
| 179 | + |
72 | 180 | void softHSMLog(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...) |
73 | 181 | { |
74 | 182 | if (loglevel > softLogLevel) return; |
@@ -98,12 +206,22 @@ void softHSMLog(const int loglevel, const char* functionName, const char* fileNa |
98 | 206 | vsnprintf(&logMessage[0], 4096, format, args); |
99 | 207 | va_end(args); |
100 | 208 |
|
101 | | - // And log it |
102 | | - syslog(loglevel, "%s%s", prepend.str().c_str(), &logMessage[0]); |
| 209 | + const char* msgText = &logMessage[0]; |
| 210 | + std::string prependStr = prepend.str(); |
| 211 | + const char* prependText = prependStr.c_str(); |
| 212 | + |
| 213 | + // Log to file if configured, otherwise use syslog |
| 214 | + if (logFile != nullptr) |
| 215 | + { |
| 216 | + writeLogToFile(loglevel, prependText, msgText); |
| 217 | + } |
| 218 | + else |
| 219 | + { |
| 220 | + syslog(loglevel, "%s%s", prependText, msgText); |
| 221 | + } |
103 | 222 |
|
104 | 223 | #ifdef DEBUG_LOG_STDERR |
105 | | - fprintf(stderr, "%s%s\n", prepend.str().c_str(), &logMessage[0]); |
| 224 | + fprintf(stderr, "%s%s\n", prependText, msgText); |
106 | 225 | fflush(stderr); |
107 | | -#endif // DEBUG_LOG_STDERR |
| 226 | +#endif |
108 | 227 | } |
109 | | - |
|
0 commit comments