OpenCPN Partial API docs
Loading...
Searching...
No Matches
logger.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2013 by David S. Register *
3 * Copyright (C) 2022 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program 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 General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
26#include <algorithm>
27#include <iomanip>
28#include <map>
29#include <sstream>
30#include <string>
31
32#include <wx/datetime.h>
33#include <wx/filename.h>
34
35#include "model/logger.h"
36
37const wxLogLevel OcpnLog::LOG_BADLEVEL = wxLOG_Max + 1;
38
39const static std::map<wxLogLevel, const char*> name_by_level = {
40 {wxLOG_FatalError, "FATALERR"}, {wxLOG_Error, "ERROR"},
41 {wxLOG_Warning, "WARNING"}, {wxLOG_Message, "MESSAGE"},
42 {wxLOG_Status, "STATUS"}, {wxLOG_Info, "INFO"},
43 {wxLOG_Debug, "DEBUG"}, {wxLOG_Trace, "TRACE"},
44 {wxLOG_Progress, "PROGRESS"}};
45
46static std::map<std::string, wxLogLevel> level_by_name;
47
48static std::string basename(const std::string path) {
49 size_t pos = path.rfind(wxFileName::GetPathSeparator(), path.length());
50 return pos == std::string::npos ? path : path.substr(pos + 1);
51}
52
53static void init_level_by_name() {
54 for (auto it = name_by_level.begin(); it != name_by_level.end(); it++) {
55 level_by_name[std::string(it->second)] = it->first;
56 }
57}
58
59static std::string timeStamp() {
60 wxDateTime now = wxDateTime::UNow();
61 std::stringstream stamp;
62 stamp << std::setfill('0') << std::setw(2) << now.GetHour() << ":"
63 << std::setw(2) << now.GetMinute() << ":" << std::setw(2)
64 << now.GetSecond() << "." << std::setw(3) << now.GetMillisecond();
65 return stamp.str();
66}
67
68std::string OcpnLog::level2str(wxLogLevel level) {
69 auto search = name_by_level.find(level);
70 return search == name_by_level.end() ? "Unknown level" : search->second;
71}
72
73wxLogLevel OcpnLog::str2level(const char* string) {
74 if (level_by_name.size() == 0) {
75 init_level_by_name();
76 }
77 std::string key(string);
78 std::transform(key.begin(), key.end(), key.begin(), ::toupper);
79 auto search = level_by_name.find(key);
80 return search == level_by_name.end() ? LOG_BADLEVEL : search->second;
81}
82
83OcpnLog::OcpnLog(const char* path) {
84 log.open(path, std::fstream::out | std::fstream::app);
85}
86
87OcpnLog::~OcpnLog() { log.close(); }
88
89void OcpnLog::Flush() {
90 wxLog::Flush();
91 log.flush();
92}
93
94void OcpnLog::DoLogRecord(wxLogLevel level, const wxString& msg,
95 const wxLogRecordInfo& info) {
96 std::ostringstream oss;
97 oss << timeStamp() << " " << std::setw(7) << level2str(level) << " "
98 << basename(info.filename) << ":" << info.line << " " << msg << std::endl;
99 log << oss.str();
100}
101
102Logger::Logger() : info("", 0, "", ""), level(wxLOG_Info) {};
103
104Logger::~Logger() {
105 wxString msg(os.str());
106 wxLog* log = wxLog::GetActiveTarget();
107 auto ocpnLog = dynamic_cast<OcpnLog*>(log);
108 if (ocpnLog) {
109 ocpnLog->LogRecord(level, msg, info);
110 }
111}
112
113std::ostream& Logger::get(wxLogLevel l, const char* path, int line) {
114 info.filename = path;
115 info.line = line;
116 level = l;
117 return os;
118}
119
120void Logger::logRecord(wxLogLevel level, const char* msg,
121 const wxLogRecordInfo info) {
122 wxLog* log = wxLog::GetActiveTarget();
123 auto ocpnLog = dynamic_cast<OcpnLog*>(log);
124 if (ocpnLog) {
125 ocpnLog->LogRecord(level, wxString(msg), info);
126 }
127}
128
129void Logger::logMessage(wxLogLevel level, const char* path, int line,
130 const char* fmt, ...) {
131 wxLogRecordInfo info(__FILE__, __LINE__, "", "");
132 char buf[1024];
133 va_list ap;
134 va_start(ap, fmt);
135 vsnprintf(buf, sizeof(buf), fmt, ap);
136 va_end(ap);
137 auto log = dynamic_cast<OcpnLog*>(wxLog::GetActiveTarget());
138 if (log) {
139 log->LogRecord(level, buf, info);
140 }
141}
142
143void CountedLogFilter::Log(const std::string& message) {
144 m_not_logged += 1;
145 if (m_not_logged < m_count) return;
146
147 wxLogGeneric(m_level, message.c_str());
148 wxLogGeneric(m_level, "Previous message suppressed %d times", m_count);
149 m_not_logged = 0;
150}
151
152void TimedLogFilter::Log(const std::string& message) {
153 auto now = std::chrono::steady_clock::now();
154 m_not_logged += 1;
155 if (now - m_last_logged < m_interval) return;
156
157 wxLogGeneric(m_level, message.c_str());
158 wxLogGeneric(m_level, "Previous message suppressed %d times", m_not_logged);
159 m_not_logged = 0;
160 m_last_logged = now;
161}
void Log(const std::string &message)
Log a repeated message after suppressing n ones.
Definition logger.cpp:143
void logRecord(wxLogLevel level, const char *msg, const wxLogRecordInfo info)
DoLogRecord public wrapper.
Definition logger.cpp:120
Customized logger class appending to a file providing:
Definition logger.h:88
OcpnLog(const char *path)
Create logger appending to given filename.
Definition logger.cpp:83
void Log(const std::string &message)
Log a repeated message after interval seconds.
Definition logger.cpp:152
Enhanced logging interface on top of wx/log.h.