In
The Case For C+-, I talked about writing quick tools in a simple C style, but taking advantage of the C++ standard library, primarily the dynamic data structures. It ends up being C++ without any (or just a few) user-defined classes, so is something of a lightweight object-oriented approach (yes, yes, I'm sure OO purists are barfing at the thought). The main benefit is fast coding.
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.
The decision on which choice to use is system-dependent. If memory is cheap and plentiful, and file I/O is relatively expensive, either in terms of time or charges to transfer data over a data link (maybe the data is remote, accessed over a cellular link), then the single-pass solution is best, choice #1.
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.
=-=-=-=-
|