1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2010 Licq Developers <licq-dev@googlegroups.com>
4 *
5 * Please refer to the COPYRIGHT file distributed with this source
6 * distribution for the names of the individual contributors.
7 *
8 * Licq 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 * Licq 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 Licq; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <licq/logging/logutils.h>
24
25 #include <cstdio>
26 #include <iomanip>
27 #include <sstream>
28
29 extern const unsigned int PacketBit;
30
31 using namespace Licq;
32
levelInBitmask(Log::Level level,unsigned int bitmask)33 bool LogUtils::levelInBitmask(Log::Level level, unsigned int bitmask)
34 {
35 return bitmask & (1 << level);
36 }
37
packetInBitmask(unsigned int bitmask)38 bool LogUtils::packetInBitmask(unsigned int bitmask)
39 {
40 return bitmask & PacketBit;
41 }
42
convertOldBitmaskToNew(int levels)43 unsigned int LogUtils::convertOldBitmaskToNew(int levels)
44 {
45 unsigned int mask = 0;
46 mask |= (levels & 0x1) ? (1 << Log::Info) : 0;
47 mask |= (levels & 0x2) ? (1 << Log::Unknown) : 0;
48 mask |= (levels & 0x4) ? (1 << Log::Error) : 0;
49 mask |= (levels & 0x8) ? (1 << Log::Warning) : 0;
50
51 mask |= (levels & 0x10) ? (1 << Log::Debug) : 0;
52 mask |= (levels & 0x10) ? PacketBit : 0;
53
54 return mask;
55 }
56
levelToString(Log::Level level)57 const char* LogUtils::levelToString(Log::Level level)
58 {
59 switch (level)
60 {
61 case Log::Unknown:
62 return "unknown";
63 case Log::Info:
64 return "info";
65 case Log::Warning:
66 return "warning";
67 case Log::Error:
68 return "error";
69 case Log::Debug:
70 return "debug";
71 }
72 return "?????";
73 }
74
levelToShortString(Log::Level level)75 const char* LogUtils::levelToShortString(Log::Level level)
76 {
77 switch (level)
78 {
79 case Log::Unknown:
80 return "UNK";
81 case Log::Info:
82 return "INF";
83 case Log::Warning:
84 return "WAR";
85 case Log::Error:
86 return "ERR";
87 case Log::Debug:
88 return "DBG";
89 }
90 return "???";
91 }
92
timeToString(const LogSink::Message::Time & msgTime)93 std::string LogUtils::timeToString(const LogSink::Message::Time& msgTime)
94 {
95 time_t t = msgTime.sec;
96 tm time;
97 ::localtime_r(&t, &time);
98
99 char buffer[8 + 4 + 1];
100 ::strftime(buffer, 8 + 1, "%H:%M:%S", &time);
101 ::snprintf(&buffer[8], 4 + 1, ".%03u", msgTime.msec);
102
103 return buffer;
104 }
105
packetToString(std::ostream & os,LogSink::Message::Ptr message)106 static std::ostream& packetToString(
107 std::ostream& os, LogSink::Message::Ptr message)
108 {
109 const std::vector<uint8_t>& packet = message->packet;
110
111 const size_t bytesPerRow = 16;
112 const size_t maxRows = 512;
113 const size_t bytesToPrint = std::min(bytesPerRow * maxRows, packet.size());
114
115 const std::string prefix(5, ' ');
116
117 char ascii[bytesPerRow + 1];
118 ascii[bytesPerRow] = '\0';
119
120 // Save current flags
121 const std::ios_base::fmtflags flags = os.flags();
122
123 os << std::hex << std::uppercase;
124 using std::setw; using std::setfill;
125
126 for (size_t addr = 0; addr < bytesToPrint; addr++)
127 {
128 const size_t pos = addr % bytesPerRow;
129
130 // Print the address at the start of the row
131 if (pos == 0)
132 os << prefix << setw(4) << setfill('0') << addr << ':';
133 // Or an extra space in the middle
134 else if (pos == (bytesPerRow / 2))
135 os << ' ';
136
137 const uint8_t byte = packet[addr];
138
139 // Print the byte in hex
140 os << ' ' << setw(2) << static_cast<uint16_t>(byte);
141
142 // Save the ascii representation (if available; otherwise '.')
143 ascii[pos] = std::isprint(byte) ? byte : '.';
144
145 // Print the ascii version at the end of the row
146 if (pos + 1 == bytesPerRow || addr + 1 == bytesToPrint)
147 {
148 ascii[pos + 1] = '\0';
149
150 // Number of bytes needed for a "full" row
151 const size_t padBytes = bytesPerRow - (pos + 1);
152
153 // Print 3 spaces for each missing byte
154 size_t padding = padBytes * 3;
155
156 // Add one extra space to compensate for the extra space in the middle
157 if (pos <= (bytesPerRow / 2))
158 padding += 1;
159
160 // Separate hex and ascii version with 3 spaces
161 padding += 3;
162
163 os << std::string(padding, ' ') << ascii;
164
165 // Print newline on all but the last line
166 if (addr + 1 != bytesToPrint)
167 os << "\n";
168 }
169 }
170
171 // Print the address range for bytes not printed
172 if (bytesToPrint != packet.size())
173 {
174 os << "\n" << prefix << setw(4) << setfill('0') << bytesToPrint
175 << " - " << setw(4) << packet.size() - 1 << ": ...";
176 }
177
178 // Restore flags
179 os.flags(flags);
180 return os;
181 }
182
packetToString(LogSink::Message::Ptr message)183 std::string LogUtils::packetToString(LogSink::Message::Ptr message)
184 {
185 std::ostringstream ss;
186 ::packetToString(ss, message);
187 return ss.str();
188 }
189