bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
BESLog.cc
1// BESLog.cc
2
3// This file is part of bes, A C++ back-end server implementation framework
4// for the OPeNDAP Data Access Protocol.
5
6// Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7// Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact University Corporation for Atmospheric Research at
24// 3080 Center Green Drive, Boulder, CO 80301
25
26// (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27// Please read the full copyright statement in the file COPYRIGHT_UCAR.
28//
29// Authors:
30// pwest Patrick West <pwest@ucar.edu>
31// jgarcia Jose Garcia <jgarcia@ucar.edu>
32
33#include "config.h"
34
35#include <iostream>
36#include <ctime>
37#include <string>
38#include <sstream>
39
40#include "BESLog.h"
41#include "BESDebug.h"
42#include "BESUtil.h"
43#include "TheBESKeys.h"
44#include "BESInternalFatalError.h"
45
46#if HAVE_UNISTD_H
47#include <unistd.h>
48#endif
49
50#define MODULE "bes"
51#define prolog std::string("BESLog::").append(__func__).append("() - ")
52
53using namespace std;
54
55BESLog *BESLog::d_instance = nullptr;
56const string BESLog::mark = string("|&|");
57
58
78
79 bool found = false;
80 try {
81 d_instance_id = TheBESKeys::TheKeys()->read_string_key("AWS.instance-id", "-");
82 }
83 catch (BESInternalFatalError &bife) {
84 stringstream msg;
85 msg << prolog << "ERROR - Caught BESInternalFatalError! Will re-throw. Message: " << bife.get_message() << " File: " << bife.get_file() << " Line: " << bife.get_line() << endl;
86 BESDEBUG(MODULE,msg.str());
87 cerr << msg.str();
88 throw;
89 }
90 catch (...) {
91 stringstream msg;
92 msg << prolog << "FATAL ERROR: Caught unknown exception! Unable to determine log file name." << endl;
93 BESDEBUG(MODULE,msg.str());
94 cerr << msg.str();
95 throw BESInternalFatalError(msg.str(), __FILE__, __LINE__);
96 }
97
98 // Find the log filename.
99 try {
100 TheBESKeys::TheKeys()->get_value("BES.LogName", d_file_name, found);
101 }
102 catch (BESInternalFatalError &bife) {
103 stringstream msg;
104 msg << prolog << "ERROR - Caught BESInternalFatalError! Will re-throw. Message: " << bife.get_message() << " File: " << bife.get_file() << " Line: " << bife.get_line() << endl;
105 BESDEBUG(MODULE,msg.str());
106 cerr << msg.str();
107 throw;
108 }
109 catch (...) {
110 stringstream msg;
111 msg << prolog << "FATAL ERROR: Caught unknown exception! Unable to determine log file name." << endl;
112 BESDEBUG(MODULE,msg.str());
113 cerr << msg.str();
114 throw BESInternalFatalError(msg.str(), __FILE__, __LINE__);
115 }
116
117
118 // By default, use UTC in the logs.
119 found = false;
120 try {
121 string local_time;
122 TheBESKeys::TheKeys()->get_value("BES.LogTimeLocal", local_time, found);
123 d_use_local_time = found && (BESUtil::lowercase(local_time) == "yes");
124 BESDEBUG(MODULE, prolog << "d_use_local_time: " << (d_use_local_time?"true":"false") << endl);
125 }
126 catch (...) {
127 stringstream err;
128 err << prolog << "FATAL ERROR: Caught unknown exception. Failed to read the value of BES.LogTimeLocal" << endl;
129 BESDEBUG(MODULE,err.str());
130 cerr << err.str() << endl;
131 throw BESInternalFatalError(err.str(), __FILE__, __LINE__);
132 }
133
134 if (d_file_name.empty()) {
135 stringstream err;
136 err << prolog << "FATAL ERROR: unable to determine log file name. ";
137 err << "Please set BES.LogName in your initialization file" << endl;
138 BESDEBUG(MODULE,err.str());
139 cerr << err.str() << endl;
140 throw BESInternalFatalError(err.str(), __FILE__, __LINE__);
141 }
142
143 d_file_buffer = new ofstream(d_file_name.c_str(), ios::out | ios::app);
144 if (!(*d_file_buffer)) {
145 stringstream err;
146 err << prolog << "BES Fatal; cannot open log file " + d_file_name + "." << endl;
147 BESDEBUG(MODULE,err.str());
148 cerr << err.str() << endl;
149 throw BESInternalFatalError(err.str(), __FILE__, __LINE__);
150 }
151
152 found = false;
153 string s;
154 TheBESKeys::TheKeys()->get_value("BES.LogVerbose", s, found);
155 d_verbose = found && (BESUtil::lowercase(s) == "yes");
156 BESDEBUG(MODULE, prolog << "d_verbose: " << (d_verbose?"true":"false") << endl);
157
158 found = false;
159 s = "";
160 TheBESKeys::TheKeys()->get_value("BES.LogUnixTime", s, found);
161 d_use_unix_time = found && (BESUtil::lowercase(s)=="true");
162 BESDEBUG(MODULE, prolog << "d_use_unix_time: " << (d_use_unix_time?"true":"false") << endl);
163
164 // Set the pid and build the log rord prolog base...
165 update_pid();
166}
167
173{
174 d_file_buffer->close();
175 delete d_file_buffer;
176 d_file_buffer = nullptr;
177}
178
183{
184 auto pid = getpid();
185 d_pid = to_string(pid);
186 d_log_record_prolog_base = mark + d_instance_id + mark + d_pid + mark;
187 return pid;
188}
189
190
200std::string BESLog::log_record_begin() const {
201 string log_record_prolog;
202
203 time_t now;
204 time(&now);
205 if(d_use_unix_time){
206 log_record_prolog = std::to_string(now);
207 }
208 else {
209 char buf[sizeof "YYYY-MM-DDTHH:MM:SS zones"];
210 tm date_time{};
211 if (!d_use_local_time){
212 gmtime_r(&now, &date_time);
213 }
214 else{
215 localtime_r(&now, &date_time);
216 }
217 (void)strftime(buf, sizeof buf, "%FT%T %Z", &date_time);
218 log_record_prolog = buf;
219 }
220
221 log_record_prolog += d_log_record_prolog_base + get_request_id() + mark;
222 return log_record_prolog;
223}
224
225
231void BESLog::log_record(const std::string &lrt, const std::string &msg) const {
232
233 *d_file_buffer << log_record_begin() << lrt << mark << msg ;
234 if(!msg.empty() && msg.back() != '\n')
235 *d_file_buffer << "\n";
236
237 *d_file_buffer << flush;
238}
239
245void BESLog::trace_log_record(const std::string &lrt, const std::string &msg, const std::string &file, const int line) const {
246
247 *d_file_buffer << log_record_begin() << "trace-" << lrt << mark;
248 *d_file_buffer << file << mark << line << mark << msg ;
249 if(!msg.empty() && msg.back() != '\n')
250 *d_file_buffer << "\n";
251
252 *d_file_buffer << flush;
253}
254
262void BESLog::dump(ostream &strm) const
263{
264 strm << BESIndent::LMarg << "BESLog::dump - (" << (void *) this << ")\n";
265 BESIndent::Indent();
266 strm << BESIndent::LMarg << " log file: " << d_file_name;
267 if (d_file_buffer && *d_file_buffer) {
268 strm << BESIndent::LMarg << " (log is valid)\n";
269 }
270 else {
271 strm << BESIndent::LMarg << " (log is NOT valid)\n";
272 }
273 strm << BESIndent::LMarg << " d_verbose: " << (d_verbose?"enabled":"disable") << "\n";
274 strm << BESIndent::LMarg << "d_instance_id: " << d_instance_id << "\n";
275 strm << BESIndent::LMarg << " d_pid: " << d_pid << "\n";
276 BESIndent::UnIndent();
277}
278
282void BESLog::set_request_id(const std::string &id){
283 request_id = id;
284 BESDEBUG(MODULE, "request_id: " << request_id << endl);
285}
286
287
288
289BESLog *
290BESLog::TheLog()
291{
292 if (d_instance == nullptr) {
293 d_instance = new BESLog;
294 }
295 return d_instance;
296}
297
unsigned int get_line() const
get the line number where the exception was thrown
Definition BESError.h:148
std::string get_file() const
get the file name where the exception was thrown
Definition BESError.h:140
std::string get_message() const
get the error message for this exception
Definition BESError.h:132
exception thrown if an internal error is found and is fatal to the BES
Provides a mechanism for applications to log information to an external file.
Definition BESLog.h:114
void set_request_id(const std::string &id)
Sets the current request id (cached in BESLog) to id.
Definition BESLog.cc:282
pid_t update_pid()
Update the d_pid and the d_log_record_prolog_base values.
Definition BESLog.cc:182
void log_record(const std::string &record_type, const std::string &msg) const
Writes msg to a log record with type lrt.
Definition BESLog.cc:231
void trace_log_record(const std::string &record_type, const std::string &msg, const std::string &file, int line) const
Writes msg, file, and line to a trace log record with type lrt.
Definition BESLog.cc:245
std::string log_record_begin() const
Protected method that returns a string with the first fields of a log record.
Definition BESLog.cc:200
void dump(std::ostream &strm) const override
dumps information about this object
Definition BESLog.cc:262
~BESLog() override
Cleans up the logging mechanism.
Definition BESLog.cc:172
BESLog()
constructor that sets up logging for the application.
Definition BESLog.cc:77
static std::string lowercase(const std::string &s)
Definition BESUtil.cc:257
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
Access to the singleton.
Definition TheBESKeys.cc:85
static std::string read_string_key(const std::string &key, const std::string &default_value)
Read a string-valued key from the bes.conf file.