Skip to content

Commit 40c498a

Browse files
committed
Introduce log.file config option to log to file
1 parent eba7ac6 commit 40c498a

4 files changed

Lines changed: 119 additions & 6 deletions

File tree

src/lib/SoftHSM.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,12 @@ 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
{
@@ -637,6 +643,9 @@ CK_RV SoftHSM::C_Finalize(CK_VOID_PTR pReserved)
637643
CryptoFactory::reset();
638644
SecureMemoryRegistry::reset();
639645

646+
// Close log file if open
647+
closeLogFile();
648+
640649
isInitialised = false;
641650

642651
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: 107 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,13 @@
3838
#include <stdio.h>
3939
#include <sstream>
4040
#include <vector>
41+
#include <time.h>
4142
#include "log.h"
43+
#include "MutexFactory.h"
4244

4345
int softLogLevel = LOG_DEBUG;
46+
static FILE* logFile = nullptr;
47+
static Mutex* logMutex = nullptr;
4448

4549
bool setLogLevel(const std::string &loglevel)
4650
{
@@ -69,6 +73,93 @@ bool setLogLevel(const std::string &loglevel)
6973
return true;
7074
}
7175

76+
bool setLogFile(const std::string &logFilePath)
77+
{
78+
// Quick return without creating mutex for default configuration
79+
if (logFilePath.empty() && logFile == nullptr)
80+
{
81+
return true;
82+
}
83+
84+
if (logMutex == nullptr)
85+
{
86+
logMutex = MutexFactory::i()->getMutex();
87+
}
88+
89+
MutexLocker lock(logMutex);
90+
91+
if (logFile != nullptr)
92+
{
93+
fclose(logFile);
94+
logFile = nullptr;
95+
}
96+
97+
if (logFilePath.empty())
98+
{
99+
return true;
100+
}
101+
102+
logFile = fopen(logFilePath.c_str(), "a");
103+
if (logFile == nullptr)
104+
{
105+
syslog(LOG_ERR, "Failed to open log file: %s, using syslog only", logFilePath.c_str());
106+
return false;
107+
}
108+
109+
return true;
110+
}
111+
112+
void closeLogFile()
113+
{
114+
if (logMutex != nullptr)
115+
{
116+
MutexLocker lock(logMutex);
117+
118+
if (logFile != nullptr)
119+
{
120+
fclose(logFile);
121+
logFile = nullptr;
122+
}
123+
}
124+
125+
if (logMutex != nullptr)
126+
{
127+
MutexFactory::i()->recycleMutex(logMutex);
128+
logMutex = nullptr;
129+
}
130+
}
131+
132+
static const char* getLevelString(int loglevel)
133+
{
134+
switch(loglevel)
135+
{
136+
case LOG_ERR: return "ERROR";
137+
case LOG_WARNING: return "WARNING";
138+
case LOG_INFO: return "INFO";
139+
case LOG_DEBUG: return "DEBUG";
140+
default: return "UNKNOWN";
141+
}
142+
}
143+
144+
static void writeLogToFile(const int loglevel, const char* prependText, const char* msgText)
145+
{
146+
MutexLocker lock(logMutex);
147+
148+
time_t now = time(nullptr);
149+
struct tm timeinfo;
150+
char timeStr[64];
151+
152+
#ifdef _WIN32
153+
localtime_s(&timeinfo, &now);
154+
#else
155+
localtime_r(&now, &timeinfo);
156+
#endif
157+
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &timeinfo);
158+
159+
fprintf(logFile, "%s %s: %s%s\n", timeStr, getLevelString(loglevel), prependText, msgText);
160+
fflush(logFile);
161+
}
162+
72163
void softHSMLog(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...)
73164
{
74165
if (loglevel > softLogLevel) return;
@@ -98,12 +189,22 @@ void softHSMLog(const int loglevel, const char* functionName, const char* fileNa
98189
vsnprintf(&logMessage[0], 4096, format, args);
99190
va_end(args);
100191

101-
// And log it
102-
syslog(loglevel, "%s%s", prepend.str().c_str(), &logMessage[0]);
192+
const char* msgText = &logMessage[0];
193+
std::string prependStr = prepend.str();
194+
const char* prependText = prependStr.c_str();
195+
196+
// Log to file if configured, otherwise use syslog
197+
if (logFile != nullptr)
198+
{
199+
writeLogToFile(loglevel, prependText, msgText);
200+
}
201+
else
202+
{
203+
syslog(loglevel, "%s%s", prependText, msgText);
204+
}
103205

104206
#ifdef DEBUG_LOG_STDERR
105-
fprintf(stderr, "%s%s\n", prepend.str().c_str(), &logMessage[0]);
207+
fprintf(stderr, "%s%s\n", prependText, msgText);
106208
fflush(stderr);
107-
#endif // DEBUG_LOG_STDERR
209+
#endif
108210
}
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)