There I showed as an example the msgresolve tool, which I used to resolve messages logged by an IOT device (the client) and its server. This is a lot of string processing and cross-indexing, with logs containing potentially thousands or tens of thousands of messages.
Shortly after I had completed msgresolve, I needed to have a tool to help me sift through large text files of server logs, logging the TCP connections made by clients and their subsequent activity. I was chasing down a problem where some of the connections were shutting down sooner than expected.
I wasn't sure what was causing the early shutdowns, and wasn't even sure initially which connections had experienced it, so I wanted to be able to gather all the lines for a given connection and list them out for tracing through, for each connection.
That would help me identify the ones that were live at the end of the log sample vs. the ones that had ended early. The log entries for hundreds of connections were all intermixed.
Armed with the methods I had used in msgresolve.cpp, conceptual design was easy. I wanted an ordered list of connections, and associated with each one, the sequential list of log entries associated with the connection.
There were also connections with some internal addresses I wanted to ignore. I could have done this filtering with grep, but it was easy enough to build the capability into the program so that it could stand alone. That also helped me explore some additional string processing functions.
Given that architecture, the data structure I needed was a std::map that mapped a string (the connection identification) to a std::list of strings (the log lines for the connection).
I had the program working in less than an hour. Then I spent at least another hour screwing around with the timestamps in the log entries, figuring out how to process them and deciding what to do with them. Then a little more time on refactoring and cleanup.
Throughout, I used a sample log file that had entries for several connections, including addresses I wanted to skip. I used that as a simple unit test to exercise the code paths.
The resulting code provided the impetus for a simple generalized string processing module, which I'll cover in another post. But you can see some clear patterns emerging in this code.
Doing quick tools like this is fun and very satisfying. It makes your serotonin flow. You have a problem you need to deal with, so you sit down and spew a bunch of code in a short time, refine it, and use the results.
This is actually quite different from long-term product development. That kind of work has its intense coding phases, but once the initial version of the product is out, a lot of the work is much smaller surgical changes.
Even fitting a major new feature in often involves many small bits of code scattered throughout the larger code base, integrating the tendrils. Getting that to work has a different kind of satisfaction.
Design Choices
These tools also give you a chance to think about different approaches. You can balance the variables of memory consumption, CPU consumption, I/O consumption, time, and code complexity (that is, ease of writing and maintaining the code, and compiled code space consumption, not algorithmic complexity) for a given situation.
For instance, the log files I was dealing with had over a million lines of data, some 200MB worth covering hundreds of connections.
That meant I had several choices:
- I could load all the data into memory and then print it out in an orderly manner. This is a single-pass solution, that consumes large amounts of memory.
- I could scan the file once, identifying all the individual connections, then for each connection, scan the file from beginning to end to read and print their lines. This a multi-pass solution that requires little memory but significant file I/O.
- I could scan the file once, and for each identified connection, track the file position of the first and last line, then for each connection, just scan that range of the file. This is a multi-pass solution that reduces the total file I/O for a negligible increase in memory.
- I could do the same thing, but instead of tracking just the first and last line file positions, build a list of the file position and length of each line, then on each pass, just skip directly to the locations of the lines. This is still multi-pass, but significantly reduces the total file I/O because it only visits each file position twice, requiring a bit more complexity and a bit more memory.
On a small-memory system, a multi-pass solution is better, and you just have to live with the extra I/O. In that case, choice #4, which is the most complicated code, has the best compromise of low memory and low I/O consumption.
Although if you're really pressed for code space, the simplest multipass solution that iterates over the entire file for each connection is the better choice, #2.
Realistically though, you don't run tools such as this locally on small systems. Where possible, you offload the data to a larger system and run the tools offline.
In this case, I'm running on a Mac with 16GB of memory. Slurping up a 200MB text file and holding everything in memory is nothing. So the single-pass solution is the way to go.
Loading The Data
The log file may just be a chronological sample of all the activity logged by the server, so some connections will already exist at the start of the log, and some will remain at the end. Meanwhile, connection starts and terminations will appear in the log.
The program parses the lines from the log to find connection lines (i.e. some activity for a given connection). It identifies them by looking for a connection ID, which consists of an IPv4 address/port pair (a remote socket ID), and may optionally include a hexadecimal client ID.
It uses just the socket ID as the connection ID, which is the key to the connection map. When it finds a new connection ID, it adds it to the map with an empty list. For each connection line, it finds the connection map entry and appends the line to the list of lines for that connection.
As it loads connection lines, it filters them against the set of IP addresses to skip (these skip address are due to logging of other types of connections besides the client connections). That helps reduce the noise from a large log file.
Printing The Data
The program prints the connections by first iterating through the map and printing out a summary of each one: the connection ID, the number of lines, the duration of the connection data found in the log, and how its lifetime relates to the overall log. Since the map is an ordered structure, printing connections is always in sorted order by connection ID (though string sorted, not numeric sorted).
Then it makes a second pass through the connection map, iterating through each line for each connection and printing it out, with separators between connections. It prints a header and summary line before and after the activity lines for each connection, showing where the connection starts and ends relative to the start and end of the log.
As a last quick change, I added a threshold time value to clearly identify connections that ended at least 60 seconds before the end of the log. This would be a good candidate for a command-line parameter to override the default threshold.
All the output lines have unique greppable features or keywords so you can use other tools for additional postprocessing or extraction. For instance, I could grep out the end summary line of each connection, and maybe the last couple of activity lines before it, to see how each connection ended up. I could use the "threshold exceeded" indication to identify the ones that had ended early.
Some Design Evolution
This program adds the isMember() function, which determines whether a string is a member of a set of strings. Since my usage here was intended to deal with a small set and I had other functions that had similar iterative structure, in the heat of battle I quickly coded it as a linear search of a vector of strings.
That worked fine here, but as I pulled a bunch of this code out into a general string processing module, I realized that was a bad choice, because it's an O(N) search.
That became especially bad when I wanted an overload that took a vector of strings and determined if they were all members. That meant an O(M) repetition of O(N) searches: an O(M*N) or effectively O(N^2) algorithm.
That gets out of hand fast as M and N get larger. Meanwhile, the std::unordered_set is perfect for this, an O(1) algorithm for single searches, and an O(M) algorithm when repeated for M items.
I've left the original isMember() implementation here as an example of the evolution of a concept as you generalize it for other uses.
I also threw in a few overloads that I didn't end up using, but that set the stage for running with the concept in the string processing module. More discussion of that in the post containing the module.
The Result
This program turned out to be another fun exercise in string processing once I had built the basic support functions and could see the problem in those terms. It felt more like working in Python, and in fact just as the dict structure from msgresolve.cpp was inspired by Python, so are the split() and join() functions here.
The funny thing is that it took doing stuff in Python to make me see this approach. That points out one of the advantages of working in multiple different languages: you start seeing opportunities to apply some of the common idioms from one language in another language.
Here's logsplit.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | // Usage: logsplit <serverLog> // // Splits a server log file by IPv4 connection. Prints a // summary list of the connections, then the log lines for // each separate connection. // // This is an example of a C++ program that is written mostly // in plain C style, but that makes use of the container and // composition classes in the C++ standard library. It is a // lightweight use of C++ with no user-defined classes. // // 2018 Steve Branam <sdbranam@gmail.com> learntocode #include <iostream> #include <iomanip> #include <sstream> #include <vector> #include <list> #include <map> enum ARGS { ARGS_PROGNAME, ARGS_SERVER_LOG, ARGS_REQUIRED, ARGS_SKIP = ARGS_REQUIRED }; enum SERVER { SERVER_DATE, SERVER_TIME, SERVER_THREAD, SERVER_SEVERITY, SERVER_FUNC, SERVER_CONN, SERVER_TIME_LEN = 16, SERVER_TIMESTAMP_LEN = 28 }; enum CONN { CONN_IP, CONN_PORT, CONN_CLIENT_ID }; enum { END_TIME_THRESHOLD = 60 }; typedef std::string String; typedef std::vector<String> StringVec; typedef std::list<String> StringList; typedef std::map<String, StringList> ConnMap; typedef std::pair<String, StringList> ConnMapEntry; const char *timeFormat = "%Y-%m-%d %H:%M:%S"; StringVec skipIps; size_t lines = 0; size_t skipped = 0; String firstTimestamp; String lastTimestamp; ConnMap connections; StringVec split(const String& str, const char* delim) { char buffer[str.size() + 1]; StringVec strings; strcpy(buffer, str.c_str()); char *token = std::strtok(buffer, delim); while (token != NULL) { strings.push_back(token); token = std::strtok(NULL, delim); } return strings; } String join(const StringVec& strings, const String& sep, size_t start = 0, size_t end = 0) { String str; if (!end) { end = strings.size(); } for (size_t i = start; i < end; ++i) { str.append(strings[i]); if (i + 1 < end) { str.append(sep); } } return str; } bool isMember(const String&str, const StringVec& set) { for (size_t i = 0; i < set.size(); ++i) { if (str == set[i]) { return true; } } return false; } typedef int (*CharMatch)(int c); bool isToken(const String& token, CharMatch isMatch) { if (token.empty()) { return false; } else { for (size_t i = 0; i < token.size(); ++i) { if (!isMatch(token[i])) { return false; } } } return true; } bool isToken(const StringVec& tokens, CharMatch isMatch, size_t start = 0, size_t end = 0) { if (!end) { end = tokens.size(); } for (size_t i = start; i < end; ++i) { if (!isToken(tokens[i], isMatch)) { return false; } } return true; } bool isNumeric(const String& token) { return isToken(token, isdigit); } bool isHex(const String& token) { return isToken(token, isxdigit); } bool isNumeric(const StringVec& tokens, size_t start = 0, size_t end = 0) { return isToken(tokens, isdigit, start, end); } bool isIpv4Address(const String& str) { StringVec tokens(split(str, ".")); return ((tokens.size() == 4) && isNumeric(tokens)); } bool isIpv4Port(const String& str) { return ((str.size() <= 5) && isNumeric(str)); } bool isIpv4Socket(const StringVec& strings) { return ((strings.size() >= 2) && isIpv4Address(strings[0]) && isIpv4Port(strings[1])); } time_t getTime(const String& strTime, const char* format) { std::tm t = {}; std::istringstream ss(strTime); ss >> std::get_time(&t, format); return mktime(&t); } time_t getTime(const String& field) { // Skip opening and closing brackets. return getTime(field.substr(1, SERVER_TIMESTAMP_LEN - 2), timeFormat); } size_t getDuration(const time_t& start, const time_t& stop) { size_t seconds(difftime(stop, start)); return seconds; } size_t getDuration(const String& start, const String& stop) { return getDuration(getTime(start), getTime(stop)); } size_t getDuration(const time_t& start, const String& stop) { return getDuration(start, getTime(stop)); } size_t getDuration(const String& start, const time_t& stop) { return getDuration(getTime(start), stop); } bool isServerTime(const String& str) { if (str.size() == SERVER_TIME_LEN) { for (size_t i = 0; i < str.size(); ++i) { if (!isdigit(str[i]) && (str[i] != ':') && (str[i] != '.') && (str[i] != ']')) { return false; } } return true; } return false; } bool isConnId(const String& str) { StringVec fields(split(str, ":")); return (isIpv4Socket(fields) && (fields.size() < CONN_CLIENT_ID + 1 || isHex(fields[CONN_CLIENT_ID]))); } bool isServerConn(const StringVec& fields) { return ((fields.size() > SERVER_CONN) && isServerTime(fields[SERVER_TIME]) && isConnId(fields[SERVER_CONN])); } bool loadServer(const char* fileName) { FILE* file = std::fopen(fileName, "r"); if (file) { char buffer[1000]; while (std::fgets(buffer, sizeof(buffer), file) != NULL) { String line(buffer); StringVec fields = split(buffer, " \t"); if (isServerConn(fields)) { ++lines; lastTimestamp = line.substr(0, SERVER_TIMESTAMP_LEN); if (firstTimestamp.empty()) { firstTimestamp = lastTimestamp; } strncpy(buffer, fields[SERVER_CONN].c_str(), sizeof(buffer)); StringVec conn = split(buffer, ":"); if (isMember(conn[CONN_IP], skipIps)) { ++skipped; } else { String key(conn[CONN_IP]); key.append(":"); key.append(conn[CONN_PORT]); ConnMap::iterator match; match = connections.find(key); if (match == connections.end()) { connections.insert(ConnMapEntry(key, StringList())); match = connections.find(key); } match->second.push_back(line); } } } std::fclose(file); if (connections.empty()) { std::cout << "No connections found" << std::endl; return false; } return true; } std::cout << "Failed to open server file" << fileName << std::endl; return false; } void printSeparator() { std::cout << std::endl << "=-=-=-=-" << std::endl << std::endl; } void listConnections() { std::cout << connections.size() << " connections " << firstTimestamp << "-" << lastTimestamp << " " << lines << " lines, " << getDuration(firstTimestamp, lastTimestamp) << " sec:" << std::endl; if (skipIps.size()) { std::cout << "(skipped " << skipped << " connections with " << join(skipIps, ", ") << ")" << std::endl; } std::cout << std::endl; for (ConnMap::iterator curConn = connections.begin(); curConn != connections.end(); curConn++) { String conn(curConn->first); StringList connLogs(curConn->second); std::cout << conn << "\t" << connLogs.front().substr(0, SERVER_TIMESTAMP_LEN) << "-" << connLogs.back().substr(0, SERVER_TIMESTAMP_LEN) << " " << connLogs.size() << " lines, " << getDuration(connLogs.front(), connLogs.back()) << " sec" << std::endl; } printSeparator(); } void logConnections() { time_t timeFirst = getTime(firstTimestamp); time_t timeLast = getTime(lastTimestamp); for (ConnMap::iterator curConn = connections.begin(); curConn != connections.end(); curConn++) { String conn(curConn->first); StringList connLogs(curConn->second); size_t duration(getDuration(connLogs.front(), connLogs.back())); std::cout << "Connection " << conn << " " << connLogs.front().substr(0, SERVER_TIMESTAMP_LEN) << "-" << connLogs.back().substr(0, SERVER_TIMESTAMP_LEN) << " " << connLogs.size() << " lines, " << duration << " sec:" << std::endl << std::endl; size_t seconds = getDuration(timeFirst, connLogs.front()); std::cout << firstTimestamp << " Starts " << seconds << " sec after start of log." << std::endl; for (StringList::iterator curLog = connLogs.begin(); curLog != connLogs.end(); curLog++) { std::cout << *curLog; } seconds = getDuration(connLogs.back(), timeLast); std::cout << lastTimestamp << " " << connLogs.size() << " lines, " << duration << " sec. Ends " << seconds << " sec before end of log."; if (seconds > END_TIME_THRESHOLD) { std::cout << " Exceeds threshold."; } std::cout << std::endl; printSeparator(); } } int main(int argc, char* argv[]) { if (argc < ARGS_REQUIRED || String(argv[1]) == "-h") { std::cout << "Usage: " << argv[ARGS_PROGNAME] << " <serverLog> [<skipIps>]" << std::endl; std::cout << "Where <skipIps> is comma-separated list " << "of IP addresses to skip." << std::endl; return EXIT_FAILURE; } else { if (argc > ARGS_REQUIRED) { skipIps = split(argv[ARGS_SKIP], ","); } if (loadServer(argv[ARGS_SERVER_LOG])) { listConnections(); logConnections(); } else { return EXIT_FAILURE; } } return EXIT_SUCCESS; } |
The sample log file, conns.log:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| [2018-04-03 13:16:29.469659] [0x00007fb3ff129700] [debug] start() 10.1.180.206:30450 TCP socket receive_buffer_size=117708
[2018-04-03 13:16:29.469678] [0x00007fb3ff129700] [debug] start() 10.1.180.206:30450 TCP socket send_buffer_size=43520
[2018-04-03 13:16:29.867381] [0x00007fb3ff129700] [debug] set_idle_send_timeout() 10.1.180.206:30450 set idle send timeout to 60 seconds
[2018-04-03 13:16:29.867394] [0x00007fb3ff129700] [debug] set_idle_receive_timeout() 10.1.180.206:30450 set idle receive timeout to 120 seconds
[2018-04-03 13:16:29.867450] [0x00007fb3ff92a700] [info] handle_connected() 10.1.180.206:30450 remote connected [2423/8951]
[2018-04-03 13:16:29.959877] [0x00007fb3ff129700] [debug] install_connection() 10.1.180.206:30450:00003bd4 linkType 0
[2018-04-03 13:16:29.966599] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0x4a2137a6, 231 bytes
[2018-04-03 13:16:29.966935] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0xa11f878a, 35 bytes, msg type 3
[2018-04-03 13:17:29.967117] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x1c35386e, 29 bytes, msg type 1
[2018-04-03 13:17:29.967228] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 59 seconds
[2018-04-03 13:17:30.086722] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0xf6e3f3bf, 29 bytes
[2018-04-03 13:17:30.086813] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0xfb208d9f, 29 bytes, msg type 17
[2018-04-03 13:17:40.086722] [0x00007fb3ff129700] [debug] receive() 10.2.80.206:3050:00000bd4 RX sum 0xf6e3f3bf, 29 bytes
[2018-04-03 13:17:40.086813] [0x00007fb3ff129700] [debug] send() 10.2.80.206:3050:00000bd4 TX sum 0xfb208d9f, 29 bytes, msg type 17
[2018-04-03 13:17:30.139377] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0xa0f8a8e1, 78 bytes
[2018-04-03 13:18:29.867494] [0x00007fb3ff129700] [debug] handle_idle_receive_timeout() 127.0.0.1:32450:00003bd4 60 seconds
[2018-04-03 13:18:29.967315] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 0 seconds
[2018-04-03 13:18:30.086988] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x8fcf53f6, 29 bytes, msg type 1
[2018-04-03 13:18:30.087101] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 59 seconds
[2018-04-03 13:18:30.197029] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0x515f1d4e, 29 bytes
[2018-04-03 13:18:30.197120] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x6827d190, 29 bytes, msg type 17
[2018-04-03 13:18:30.249027] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0xda66c5c7, 78 bytes
[2018-04-03 13:19:30.087189] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 0 seconds
[2018-04-03 13:19:30.139486] [0x00007fb3ff129700] [debug] handle_idle_receive_timeout() 10.1.180.206:30450:00003bd4 60 seconds
[2018-04-03 13:19:30.197322] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x812afb16, 29 bytes, msg type 1
|
Sample run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| $ g++ logsplit.cpp -o logsplit
$ ./logsplit conns.log 127.0.0.1,3.3.3.3
2 connections [2018-04-03 13:16:29.469659]-[2018-04-03 13:19:30.197322] 25 lines, 181 sec:
(skipped 1 connections with 127.0.0.1, 3.3.3.3)
10.1.180.206:30450 [2018-04-03 13:16:29.469659]-[2018-04-03 13:19:30.197322] 22 lines, 181 sec
10.2.80.206:3050 [2018-04-03 13:17:40.086722]-[2018-04-03 13:17:40.086813] 2 lines, 0 sec
=-=-=-=-
Connection 10.1.180.206:30450 [2018-04-03 13:16:29.469659]-[2018-04-03 13:19:30.197322] 22 lines, 181 sec:
[2018-04-03 13:16:29.469659] Starts 0 sec after start of log.
[2018-04-03 13:16:29.469659] [0x00007fb3ff129700] [debug] start() 10.1.180.206:30450 TCP socket receive_buffer_size=117708
[2018-04-03 13:16:29.469678] [0x00007fb3ff129700] [debug] start() 10.1.180.206:30450 TCP socket send_buffer_size=43520
[2018-04-03 13:16:29.867381] [0x00007fb3ff129700] [debug] set_idle_send_timeout() 10.1.180.206:30450 set idle send timeout to 60 seconds
[2018-04-03 13:16:29.867394] [0x00007fb3ff129700] [debug] set_idle_receive_timeout() 10.1.180.206:30450 set idle receive timeout to 120 seconds
[2018-04-03 13:16:29.867450] [0x00007fb3ff92a700] [info] handle_connected() 10.1.180.206:30450 remote connected [2423/8951]
[2018-04-03 13:16:29.959877] [0x00007fb3ff129700] [debug] install_connection() 10.1.180.206:30450:00003bd4 linkType 0
[2018-04-03 13:16:29.966599] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0x4a2137a6, 231 bytes
[2018-04-03 13:16:29.966935] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0xa11f878a, 35 bytes, msg type 3
[2018-04-03 13:17:29.967117] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x1c35386e, 29 bytes, msg type 1
[2018-04-03 13:17:29.967228] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 59 seconds
[2018-04-03 13:17:30.086722] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0xf6e3f3bf, 29 bytes
[2018-04-03 13:17:30.086813] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0xfb208d9f, 29 bytes, msg type 17
[2018-04-03 13:17:30.139377] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0xa0f8a8e1, 78 bytes
[2018-04-03 13:18:29.967315] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 0 seconds
[2018-04-03 13:18:30.086988] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x8fcf53f6, 29 bytes, msg type 1
[2018-04-03 13:18:30.087101] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 59 seconds
[2018-04-03 13:18:30.197029] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0x515f1d4e, 29 bytes
[2018-04-03 13:18:30.197120] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x6827d190, 29 bytes, msg type 17
[2018-04-03 13:18:30.249027] [0x00007fb3ff129700] [debug] receive() 10.1.180.206:30450:00003bd4 RX sum 0xda66c5c7, 78 bytes
[2018-04-03 13:19:30.087189] [0x00007fb3ff129700] [debug] handle_idle_send_timeout() 10.1.180.206:30450:00003bd4 0 seconds
[2018-04-03 13:19:30.139486] [0x00007fb3ff129700] [debug] handle_idle_receive_timeout() 10.1.180.206:30450:00003bd4 60 seconds
[2018-04-03 13:19:30.197322] [0x00007fb3ff129700] [debug] send() 10.1.180.206:30450:00003bd4 TX sum 0x812afb16, 29 bytes, msg type 1
[2018-04-03 13:19:30.197322] 22 lines, 181 sec. Ends 0 sec before end of log.
=-=-=-=-
Connection 10.2.80.206:3050 [2018-04-03 13:17:40.086722]-[2018-04-03 13:17:40.086813] 2 lines, 0 sec:
[2018-04-03 13:16:29.469659] Starts 71 sec after start of log.
[2018-04-03 13:17:40.086722] [0x00007fb3ff129700] [debug] receive() 10.2.80.206:3050:00000bd4 RX sum 0xf6e3f3bf, 29 bytes
[2018-04-03 13:17:40.086813] [0x00007fb3ff129700] [debug] send() 10.2.80.206:3050:00000bd4 TX sum 0xfb208d9f, 29 bytes, msg type 17
[2018-04-03 13:19:30.197322] 2 lines, 0 sec. Ends 110 sec before end of log. Exceeds threshold.
=-=-=-=-
|
No comments:
Post a Comment