NAWA 0.9
Web Application Framework for C++
Log.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019-2022 Tobias Flaig.
3 *
4 * This file is part of nawa.
5 *
6 * nawa is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License,
8 * version 3, as published by the Free Software Foundation.
9 *
10 * nawa is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with nawa. If not, see <https://www.gnu.org/licenses/>.
17 */
18
24#include <atomic>
25#include <iomanip>
26#include <mutex>
27#include <nawa/Exception.h>
28#include <nawa/logging/Log.h>
29#include <nawa/oss.h>
30
31using namespace nawa;
32using namespace std;
33
34namespace {
35 struct DestructionDetector {
36 bool destructed = false;
37
38 ~DestructionDetector() { destructed = true; }
39 } destructionDetector;
40
41 bool locked = false;
42 ostream* out;
43 ofstream logFile;
44 Log::Level outputLevel = Log::Level::INFORMATIONAL;
45 bool extendedFormat = false;
46 unique_ptr<string> hostnameStr;
47 pid_t pid = 0;
48 atomic_uint instanceCount(0);
49 mutex outLock;
50}// namespace
51
52struct Log::Data {
53 string appname;
54 Level defaultLevel;
56 explicit Data(Level defaultLevel = Level::INFORMATIONAL) : defaultLevel(defaultLevel) {}
57};
58
59Log::Log() noexcept {
60 data = make_unique<Data>(Level::INFORMATIONAL);
61
62 if (instanceCount == 0) {
63 out = &cerr;
64
65 // get hostname
66 hostnameStr = make_unique<string>(oss::getSystemHostname());
67
68 // get pid
69 pid = getpid();
70 }
71
72 // appname is nawa by default
73 data->appname = "nawa";
74
75 ++instanceCount;
76}
77
78Log::Log(std::string appname, Level level) noexcept : Log() {
79 data->appname = std::move(appname);
80 data->defaultLevel = level;
81}
82
83Log::Log(Level level) noexcept : Log() {
84 data->defaultLevel = level;
85}
86
87Log::Log(Log const& other) noexcept {
88 data = make_unique<Data>(*other.data);
89 ++instanceCount;
90}
91
92Log& Log::operator=(Log const& other) noexcept {
93 if (this != &other) {
94 *data = *other.data;
95 ++instanceCount;
96 }
97 return *this;
98}
99
101 if (!destructionDetector.destructed) {
102 --instanceCount;
103 if (instanceCount == 0) {
104 if (logFile.is_open()) {
105 logFile.close();
106 }
107 locked = false;
108 }
109 } else {
110 if (logFile.is_open()) {
111 logFile.close();
112 }
113 }
114}
115
116void Log::setStream(std::ostream* os) noexcept {
117 if (!locked) {
118 out = os;
119 }
120}
121
122void Log::setOutfile(std::string const& filename) {
123 if (!locked) {
124 if (logFile.is_open()) {
125 logFile.close();
126 }
127 logFile.open(filename, ofstream::out | ofstream::app);
128 if (!logFile) {
129 throw Exception(__PRETTY_FUNCTION__, 1,
130 "Failed to open requested file for writing.");
131 }
132 out = &logFile;
133 }
134}
135
137 if (!locked) {
138 outputLevel = level;
139 }
140}
141
142void Log::setExtendedFormat(bool useExtendedFormat) {
143 if (!locked) {
144 extendedFormat = useExtendedFormat;
145 }
146}
147
148void Log::lockStream() noexcept {
149 locked = true;
150}
151
152bool Log::isLocked() noexcept {
153 return locked;
154}
155
156void Log::setAppname(std::string appname) noexcept {
157 data->appname = std::move(appname);
158}
159
160void Log::setDefaultLogLevel(Level level) noexcept {
161 data->defaultLevel = level;
162}
163
164void Log::write(std::string const& msg) {
165 write(msg, data->defaultLevel);
166}
167
168void Log::write(std::string const& msg, Level level) {
169 if (level <= outputLevel && outputLevel != Level::OFF && level != Level::OFF) {
170 auto now = time(nullptr);
171 lock_guard<mutex> l(outLock);
172 if (extendedFormat) {
173 *out << put_time(localtime(&now), "%b %d %H:%M:%S ") << *hostnameStr << ' '
174 << oss::getProgramInvocationName() << '[' << pid << "]: ";
175 }
176 cerr << "[" << data->appname << "] " << msg << endl;
177 out->flush();
178 }
179}
180
181void Log::operator()(std::string const& msg) {
182 write(msg, data->defaultLevel);
183}
184
185void Log::operator()(std::string const& msg, Level level) {
186 write(msg, level);
187}
Exception class that can be used by apps to catch errors resulting from nawa function calls.
Simple class for (not (yet) thread-safe) logging to stderr or to any other output stream.
Definition: Log.h:38
Log & operator=(Log const &other) noexcept
Definition: Log.cpp:92
virtual ~Log()
Definition: Log.cpp:100
static void setOutputLevel(Level level)
Definition: Log.cpp:136
void operator()(std::string const &msg)
Definition: Log.cpp:181
static void setOutfile(std::string const &filename)
Definition: Log.cpp:122
Level
Definition: Log.h:47
void setDefaultLogLevel(Level level) noexcept
Definition: Log.cpp:160
Log() noexcept
Definition: Log.cpp:59
static void lockStream() noexcept
Definition: Log.cpp:148
void write(std::string const &msg)
Definition: Log.cpp:164
void setAppname(std::string appname) noexcept
Definition: Log.cpp:156
static bool isLocked() noexcept
Definition: Log.cpp:152
static void setStream(std::ostream *os) noexcept
Definition: Log.cpp:116
static void setExtendedFormat(bool useExtendedFormat)
Definition: Log.cpp:142
std::string getProgramInvocationName()
Definition: oss.h:52
std::string getSystemHostname()
Definition: oss.h:42
Definition: AppInit.h:31
This file contains helpers for operating-system specific stuff.