1 /******************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2013 by David S. Register *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************
23 */
24
25 #include <algorithm>
26 #include <iomanip>
27 #include <map>
28 #include <sstream>
29 #include <string>
30
31 #include <wx/datetime.h>
32 #include <wx/filename.h>
33
34 #include "logger.h"
35
36 const wxLogLevel OcpnLog::LOG_BADLEVEL = wxLOG_Max + 1;
37
38 const static std::map<wxLogLevel, const char*> name_by_level = {
39 { wxLOG_FatalError, "FATALERR"},
40 { wxLOG_Error, "ERROR"},
41 { wxLOG_Warning, "WARNING"},
42 { wxLOG_Message, "MESSAGE"},
43 { wxLOG_Status, "STATUS"},
44 { wxLOG_Info, "INFO"},
45 { wxLOG_Debug, "DEBUG"},
46 { wxLOG_Trace, "TRACE"},
47 { wxLOG_Progress, "PROGRESS"}
48 };
49
50
51 static std::map<std::string, wxLogLevel> level_by_name;
52
53
basename(const std::string path)54 static std::string basename(const std::string path)
55 {
56 size_t pos = path.rfind(wxFileName::GetPathSeparator(), path.length());
57 return pos == std::string::npos ? path : path.substr(pos + 1);
58 }
59
60
init_level_by_name()61 static void init_level_by_name()
62 {
63 for (auto it = name_by_level.begin(); it != name_by_level.end(); it++) {
64 level_by_name[std::string(it->second)] = it->first;
65 }
66 }
67
68
timeStamp()69 static std::string timeStamp()
70 {
71 wxDateTime now = wxDateTime::UNow();
72 std::stringstream stamp;
73 stamp << std::setfill('0')
74 << std::setw(2) << now.GetHour() << ":"
75 << std::setw(2) << now.GetMinute() << ":"
76 << std::setw(2) << now.GetSecond() << "."
77 << std::setw(3) << now.GetMillisecond();
78 return stamp.str();
79 }
80
81
level2str(wxLogLevel level)82 std::string OcpnLog::level2str(wxLogLevel level)
83 {
84 auto search = name_by_level.find(level);
85 return search == name_by_level.end() ? "Unknown level" : search->second;
86 }
87
88
str2level(const char * string)89 wxLogLevel OcpnLog::str2level(const char* string)
90 {
91 if (level_by_name.size() == 0) {
92 init_level_by_name();
93 }
94 std::string key(string);
95 std::transform(key.begin(), key.end(), key.begin(), ::toupper);
96 auto search = level_by_name.find(key);
97 return search == level_by_name.end() ? LOG_BADLEVEL : search->second;
98 }
99
100
OcpnLog(const char * path)101 OcpnLog::OcpnLog(const char* path)
102 {
103 log.open(path, std::fstream::out | std::fstream::app);
104 }
105
106
~OcpnLog()107 OcpnLog::~OcpnLog()
108 {
109 log.close();
110 }
111
Flush()112 void OcpnLog::Flush()
113 {
114 wxLog::Flush();
115 log.flush();
116 }
117
DoLogRecord(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info)118 void OcpnLog::DoLogRecord(wxLogLevel level,
119 const wxString& msg,
120 const wxLogRecordInfo& info)
121 {
122 std::ostringstream oss;
123 oss << timeStamp() << " "
124 << std::setw(7) << level2str(level) << " "
125 << basename(info.filename) << ":" << info.line << " "
126 << msg << std::endl;
127 log << oss.str();
128 }
129
130
Logger()131 Logger::Logger()
132 :info("", 0, "", ""), level(wxLOG_Info) {};
133
~Logger()134 Logger::~Logger()
135 {
136 wxString msg(os.str());
137 wxLog* log = wxLog::GetActiveTarget();
138 auto ocpnLog = dynamic_cast<OcpnLog*>(log);
139 if (ocpnLog) {
140 ocpnLog->LogRecord(level, msg, info);
141 }
142 }
143
144
get(wxLogLevel l,const char * path,int line)145 std::ostream& Logger::get(wxLogLevel l, const char* path, int line)
146 {
147 info.filename = path;
148 info.line = line;
149 level = l;
150 return os;
151 }
152
153
logRecord(wxLogLevel level,const char * msg,const wxLogRecordInfo info)154 void Logger::logRecord(wxLogLevel level,
155 const char* msg,
156 const wxLogRecordInfo info)
157 {
158 wxLog* log = wxLog::GetActiveTarget();
159 auto ocpnLog = dynamic_cast<OcpnLog*>(log);
160 if (ocpnLog) {
161 ocpnLog->LogRecord(level, wxString(msg), info);
162 }
163 }
164
165
logMessage(wxLogLevel level,const char * path,int line,const char * fmt,...)166 void Logger::logMessage(wxLogLevel level, const char* path, int line,
167 const char* fmt, ...)
168 {
169 wxLogRecordInfo info(__FILE__, __LINE__, "", "");
170 char buf[1024];
171 va_list ap;
172 va_start(ap, fmt);
173 vsnprintf(buf, sizeof(buf), fmt, ap);
174 va_end(ap);
175 auto log = dynamic_cast<OcpnLog*>(wxLog::GetActiveTarget());
176 if (log) {
177 log->LogRecord(level, buf, info);
178 }
179 }
180