@@ -91,6 +91,51 @@ namespace vix::commands::logs::analyzer
9191
9292 return line;
9393 }
94+
95+ std::string detect_network_group (const std::string &line)
96+ {
97+ if (line.find (" connection reset by peer" ) != std::string::npos ||
98+ line.find (" reset by peer" ) != std::string::npos)
99+ {
100+ return " connection reset by peer" ;
101+ }
102+
103+ if (line.find (" client closed connection" ) != std::string::npos ||
104+ line.find (" client prematurely closed connection" ) != std::string::npos ||
105+ line.find (" broken pipe" ) != std::string::npos)
106+ {
107+ return " client disconnected" ;
108+ }
109+
110+ if (line.find (" upstream prematurely closed connection" ) != std::string::npos)
111+ {
112+ return " upstream disconnected" ;
113+ }
114+
115+ if (line.find (" connection refused" ) != std::string::npos ||
116+ line.find (" connect() failed" ) != std::string::npos ||
117+ line.find (" connect failed" ) != std::string::npos)
118+ {
119+ return " connection refused" ;
120+ }
121+
122+ if (line.find (" timed out" ) != std::string::npos ||
123+ line.find (" timeout" ) != std::string::npos ||
124+ line.find (" upstream timed out" ) != std::string::npos)
125+ {
126+ return " timeout" ;
127+ }
128+
129+ if (line.find (" websocket" ) != std::string::npos &&
130+ (line.find (" close" ) != std::string::npos ||
131+ line.find (" closed" ) != std::string::npos ||
132+ line.find (" disconnect" ) != std::string::npos))
133+ {
134+ return " websocket disconnected" ;
135+ }
136+
137+ return {};
138+ }
94139 }
95140
96141 RepeatedLogReport analyze_repeated_errors (
@@ -99,7 +144,8 @@ namespace vix::commands::logs::analyzer
99144 RepeatedLogReport report;
100145 report.totalLines = static_cast <int >(lines.size ());
101146
102- std::unordered_map<std::string, int > counts;
147+ std::unordered_map<std::string, int > repeatedCounts;
148+ std::unordered_map<std::string, int > networkCounts;
103149
104150 for (const std::string &line : lines)
105151 {
@@ -108,10 +154,16 @@ namespace vix::commands::logs::analyzer
108154 if (normalized.empty ())
109155 continue ;
110156
111- ++counts[normalized];
157+ ++repeatedCounts[normalized];
158+
159+ const std::string networkGroup =
160+ detect_network_group (normalized);
161+
162+ if (!networkGroup.empty ())
163+ ++networkCounts[networkGroup];
112164 }
113165
114- for (const auto &[message, count] : counts )
166+ for (const auto &[message, count] : repeatedCounts )
115167 {
116168 if (count <= 1 )
117169 continue ;
@@ -122,6 +174,14 @@ namespace vix::commands::logs::analyzer
122174 count});
123175 }
124176
177+ for (const auto &[name, count] : networkCounts)
178+ {
179+ report.networkGroups .push_back (
180+ NetworkDisconnectGroup{
181+ name,
182+ count});
183+ }
184+
125185 std::sort (
126186 report.entries .begin (),
127187 report.entries .end (),
@@ -133,9 +193,23 @@ namespace vix::commands::logs::analyzer
133193 return a.message < b.message ;
134194 });
135195
196+ std::sort (
197+ report.networkGroups .begin (),
198+ report.networkGroups .end (),
199+ [](const NetworkDisconnectGroup &a, const NetworkDisconnectGroup &b)
200+ {
201+ if (a.count != b.count )
202+ return a.count > b.count ;
203+
204+ return a.name < b.name ;
205+ });
206+
136207 report.repeatedGroups =
137208 static_cast <int >(report.entries .size ());
138209
210+ report.networkDisconnectGroups =
211+ static_cast <int >(report.networkGroups .size ());
212+
139213 return report;
140214 }
141215
@@ -160,16 +234,40 @@ namespace vix::commands::logs::analyzer
160234 vix::cli::util::ok_line (
161235 out,
162236 " no repeated errors detected" );
237+ }
238+ else
239+ {
240+ for (const RepeatedLogEntry &entry : report.entries )
241+ {
242+ vix::cli::util::kv (
243+ out,
244+ std::to_string (entry.count ) + " x" ,
245+ entry.message );
246+ }
247+ }
248+
249+ vix::cli::util::section (out, " Common Network Disconnects" );
250+
251+ vix::cli::util::kv (
252+ out,
253+ " Detected groups" ,
254+ std::to_string (report.networkDisconnectGroups ));
255+
256+ if (report.networkGroups .empty ())
257+ {
258+ vix::cli::util::ok_line (
259+ out,
260+ " no common network disconnects detected" );
163261
164262 return ;
165263 }
166264
167- for (const RepeatedLogEntry &entry : report.entries )
265+ for (const NetworkDisconnectGroup &group : report.networkGroups )
168266 {
169267 vix::cli::util::kv (
170268 out,
171- std::to_string (entry .count ) + " x" ,
172- entry. message );
269+ std::to_string (group .count ) + " x" ,
270+ group. name );
173271 }
174272 }
175273}
0 commit comments