Skip to content

Commit ed00fb2

Browse files
authored
Introduce log.file config option to log to file (#837)
1 parent 9687394 commit ed00fb2

File tree

4 files changed

+138
-6
lines changed

4 files changed

+138
-6
lines changed

src/lib/SoftHSM.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,17 @@ CK_RV SoftHSM::C_Initialize(CK_VOID_PTR pInitArgs)
574574
return CKR_GENERAL_ERROR;
575575
}
576576

577+
// Configure log file (empty string = use syslog)
578+
if (!setLogFile(Configuration::i()->getString("log.file", "")))
579+
{
580+
WARNING_MSG("Could not open log file, using syslog");
581+
}
582+
577583
// Configure object store storage backend used by all tokens.
578584
if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND)))
579585
{
580586
ERROR_MSG("Could not set the storage backend");
587+
closeLogFile();
581588
return CKR_GENERAL_ERROR;
582589
}
583590

@@ -589,6 +596,7 @@ CK_RV SoftHSM::C_Initialize(CK_VOID_PTR pInitArgs)
589596
if (!objectStore->isValid())
590597
{
591598
WARNING_MSG("Could not load the object store");
599+
closeLogFile();
592600
delete objectStore;
593601
objectStore = NULL;
594602
delete sessionObjectStore;
@@ -637,6 +645,9 @@ CK_RV SoftHSM::C_Finalize(CK_VOID_PTR pReserved)
637645
CryptoFactory::reset();
638646
SecureMemoryRegistry::reset();
639647

648+
// Close log file if open
649+
closeLogFile();
650+
640651
isInitialised = false;
641652

642653
supportedMechanisms.clear();

src/lib/common/Configuration.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const struct config Configuration::valid_config[] = {
4848
{ "objectstore.backend", CONFIG_TYPE_STRING },
4949
{ "objectstore.umask", CONFIG_TYPE_INT_OCTAL },
5050
{ "log.level", CONFIG_TYPE_STRING },
51+
{ "log.file", CONFIG_TYPE_STRING },
5152
{ "slots.removable", CONFIG_TYPE_BOOL },
5253
{ "slots.mechanisms", CONFIG_TYPE_STRING },
5354
{ "library.reset_on_fork", CONFIG_TYPE_BOOL },

src/lib/common/log.cpp

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
3030
Implements logging functions. This file is based on the concepts from
3131
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.
3333
*****************************************************************************/
3434

3535
#include "config.h"
@@ -38,9 +38,19 @@
3838
#include <stdio.h>
3939
#include <sstream>
4040
#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
4148
#include "log.h"
49+
#include "MutexFactory.h"
4250

4351
int softLogLevel = LOG_DEBUG;
52+
static FILE* logFile = nullptr;
53+
static Mutex* logMutex = nullptr;
4454

4555
bool setLogLevel(const std::string &loglevel)
4656
{
@@ -69,6 +79,104 @@ bool setLogLevel(const std::string &loglevel)
6979
return true;
7080
}
7181

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+
72180
void softHSMLog(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...)
73181
{
74182
if (loglevel > softLogLevel) return;
@@ -98,12 +206,22 @@ void softHSMLog(const int loglevel, const char* functionName, const char* fileNa
98206
vsnprintf(&logMessage[0], 4096, format, args);
99207
va_end(args);
100208

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+
}
103222

104223
#ifdef DEBUG_LOG_STDERR
105-
fprintf(stderr, "%s%s\n", prepend.str().c_str(), &logMessage[0]);
224+
fprintf(stderr, "%s%s\n", prependText, msgText);
106225
fflush(stderr);
107-
#endif // DEBUG_LOG_STDERR
226+
#endif
108227
}
109-

src/lib/common/log.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979

8080
/* Function definitions */
8181
bool setLogLevel(const std::string &loglevel);
82+
bool setLogFile(const std::string &logFilePath);
83+
void closeLogFile();
8284
void softHSMLog(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...);
8385

8486
#endif /* !_SOFTHSM_V2_LOG_H */

0 commit comments

Comments
 (0)