1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#include "stdafx.h"
#include "logger.h"
#include <libcommon/error.h>
#include <libcommon/string.h>
#include <sstream>
#include <iomanip>
Utf8FileLogSink::Utf8FileLogSink(const std::wstring &file, bool append, bool flush)
: m_flush(flush)
{
const DWORD creationDisposition = (append ? OPEN_ALWAYS : CREATE_ALWAYS);
m_logfile = CreateFileW(file.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr,
creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
if (INVALID_HANDLE_VALUE == m_logfile)
{
THROW_WINDOWS_ERROR(GetLastError(), "Open/create log file");
}
if (append && ERROR_ALREADY_EXISTS == GetLastError())
{
LARGE_INTEGER offset = { 0 };
const auto seekStatus = SetFilePointerEx(m_logfile, offset, nullptr, FILE_END);
if (FALSE == seekStatus)
{
CloseHandle(m_logfile);
THROW_WINDOWS_ERROR(GetLastError(), "Seek to end offset in existing log file");
}
}
}
Utf8FileLogSink::~Utf8FileLogSink()
{
CloseHandle(m_logfile);
}
void Utf8FileLogSink::log(const std::wstring &message)
{
auto utf8String = common::string::ToUtf8(message);
utf8String.pop_back(); // remove the null char
if (0 == utf8String.size())
{
return;
}
utf8String.push_back('\xd');
utf8String.push_back('\xa');
DWORD bytesWritten;
WriteFile(m_logfile, utf8String.data(), utf8String.size(), &bytesWritten, nullptr);
if (m_flush)
{
FlushFileBuffers(m_logfile);
}
}
void Logger::log(const std::wstring &message)
{
m_logsink->log(Compose(message, Timestamp()));
}
void Logger::log(const std::wstring &message, const std::vector<std::wstring> &details)
{
const auto timestamp = this->Timestamp();
m_logsink->log(Compose(message, timestamp));
//
// Write details with indentation.
//
for (const auto detail : details)
{
m_logsink->log(Compose(detail, timestamp, 4));
}
}
// static
std::wstring Logger::Timestamp()
{
SYSTEMTIME time;
GetLocalTime(&time);
std::wstringstream ss;
ss << L'['
<< std::right << std::setw(4) << std::setfill(L'0') << time.wYear
<< L'-'
<< std::right << std::setw(2) << std::setfill(L'0') << time.wMonth
<< L'-'
<< std::right << std::setw(2) << std::setfill(L'0') << time.wDay
<< L' '
<< std::right << std::setw(2) << std::setfill(L'0') << time.wHour
<< L':'
<< std::right << std::setw(2) << std::setfill(L'0') << time.wMinute
<< L':'
<< std::right << std::setw(2) << std::setfill(L'0') << time.wSecond
<< L'.'
<< std::right << std::setw(3) << std::setfill(L'0') << time.wMilliseconds
<< L']';
return ss.str();
}
//static
std::wstring Logger::Compose(const std::wstring &message, const std::wstring ×tamp, size_t indentation)
{
std::wstringstream ss;
ss << timestamp << L' '
<< std::wstring(indentation, L' ')
<< message;
return ss.str();
}
|