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