this repo has no description

add: support for partial samples

altagos.dev 79b09f56 6a920a07

verified
+105 -37
+105 -37
src/austin.zig
··· 172 172 var line_it_back = mem.splitBackwardsScalar(u8, line.items, ' '); 173 173 const metric_raw = line_it_back.next().?; 174 174 175 - if (!mem.containsAtLeast(u8, metric_raw, 2, ",")) return ParseError.InvalidSample; 175 + const data_raw = line.items[0 .. line.items.len - metric_raw.len - 1]; 176 + 177 + if (!mem.containsAtLeast(u8, metric_raw, 2, ",")) { 178 + self.parseFullSample(sample, data_raw, line_num) catch |err| { 179 + switch (err) { 180 + ParseError.NoPID, 181 + ParseError.InvalidPID, 182 + ParseError.NoThreadInfo, 183 + ParseError.NoIID, 184 + ParseError.InvalidIID, 185 + ParseError.NoTID, 186 + ParseError.InvalidTID, 187 + => return ParseError.InvalidSample, 188 + else => {}, 189 + } 190 + }; 191 + 192 + std.log.warn( 193 + \\No metrics found while parsing line {}, returning partial sample 194 + \\{} | {s}{s} 195 + , 196 + .{ 197 + line_num, 198 + line_num, 199 + if (line.items.len <= 80) line.items else line.items[0..80], 200 + if (line.items.len <= 80) "" else " ...", 201 + }, 202 + ); 203 + return SampleWrapper{ .partial = .{ 204 + .process = sample.process, 205 + .frames = sample.frames, 206 + } }; 207 + } 176 208 177 209 // Metric 178 210 var metric = mem.tokenizeScalar(u8, metric_raw, ','); ··· 194 226 ), 195 227 }; 196 228 197 - const data_raw = line.items[0 .. line.items.len - metric_raw.len - 1]; 198 - self.parseFullSample(sample, data_raw) catch |err| { 199 - std.log.err( 200 - "Caught {} while parsing line {} returning metrics ({}):\n{s}", 201 - .{ err, line_num, sample.metric, line.items }, 229 + self.parseFullSample(sample, data_raw, line_num) catch |err| { 230 + std.log.warn( 231 + \\Caught {} while parsing line {}, returning metrics ({}): 232 + \\{} | {s}{s} 233 + , 234 + .{ 235 + err, 236 + line_num, 237 + sample.metric, 238 + line_num, 239 + if (line.items.len <= 80) line.items else line.items[0..80], 240 + if (line.items.len <= 80) "" else " ...", 241 + }, 202 242 ); 203 243 return SampleWrapper{ .metric = sample.metric }; 204 244 }; ··· 206 246 return SampleWrapper{ .full = sample.* }; 207 247 } 208 248 209 - fn parseFullSample(self: *Parser, sample: *Sample, data_raw: []const u8) !void { 249 + fn parseFullSample(self: *Parser, sample: *Sample, data_raw: []const u8, line_num: usize) !void { 210 250 var data = std.mem.tokenizeScalar(u8, data_raw, ';'); 211 251 212 252 // PID ··· 231 271 var frames: std.ArrayList(FrameWrapper) = try .initCapacity(self.arena, 1); 232 272 233 273 while (data.next()) |frame_raw| { 234 - var frame = std.mem.tokenizeScalar(u8, frame_raw, ':'); 235 - const module = frame.next() orelse return ParseError.NoModule; 274 + const frame = self.parseFrame(frame_raw) catch |err| { 275 + switch (err) { 276 + error.InvalidFrame => { 277 + try frames.append(FrameWrapper{ .invalid = {} }); 278 + break; 279 + }, 280 + ParseError.NoModule, 281 + ParseError.InvalidLineNumber, 282 + ParseError.NoFunction, 283 + ParseError.NoLineNumber, 284 + => { 285 + std.log.warn( 286 + "Cought invalid frame while parsing line {}:\n{} | {s}{s}", 287 + .{ 288 + line_num, 289 + line_num, 290 + if (frame_raw.len <= 80) frame_raw else frame_raw[0..80], 291 + if (frame_raw.len <= 80) "" else " ...", 292 + }, 293 + ); 294 + try frames.append(FrameWrapper{ .invalid = {} }); 295 + continue; 296 + }, 297 + else => return err, 298 + } 299 + }; 300 + try frames.append(FrameWrapper{ .call_stack = frame }); 301 + } 236 302 237 - if (mem.startsWith(u8, frame_raw, "::")) { 238 - try frames.append(FrameWrapper{ .call_stack = Frame{ 239 - .module = "", 240 - .function = "", 241 - .line_number = std.fmt.parseInt(isize, module, 0) catch 242 - return ParseError.InvalidLineNumber, 243 - } }); 244 - continue; 245 - } 303 + sample.frames = try frames.toOwnedSlice(); 304 + } 305 + 306 + fn parseFrame(self: *Parser, frame_raw: []const u8) !Frame { 307 + var frame = std.mem.tokenizeScalar(u8, frame_raw, ':'); 308 + const module = frame.next() orelse return ParseError.NoModule; 309 + 310 + if (mem.startsWith(u8, frame_raw, "::")) { 311 + return Frame{ 312 + .module = "", 313 + .function = "", 314 + .line_number = std.fmt.parseInt(isize, module, 0) catch 315 + return ParseError.InvalidLineNumber, 316 + }; 317 + } 246 318 247 - if (!mem.eql(u8, module, "INVALID")) { 248 - const function = frame.next() orelse return ParseError.NoFunction; 319 + if (!mem.eql(u8, module, "INVALID")) { 320 + const function = frame.next() orelse return ParseError.NoFunction; 249 321 250 - const line_number = std.fmt.parseInt( 251 - isize, 252 - frame.next() orelse return ParseError.NoLineNumber, 253 - 0, 254 - ) catch return ParseError.InvalidLineNumber; 322 + const line_number = std.fmt.parseInt( 323 + isize, 324 + frame.next() orelse return ParseError.NoLineNumber, 325 + 0, 326 + ) catch return ParseError.InvalidLineNumber; 255 327 256 - var f: Frame = .{ .line_number = line_number }; 257 - f.module = try self.arena.alloc(u8, module.len); 258 - @memcpy(@constCast(f.module), module); 328 + var f: Frame = .{ .line_number = line_number }; 329 + f.module = try self.arena.alloc(u8, module.len); 330 + @memcpy(@constCast(f.module), module); 259 331 260 - f.function = try self.arena.alloc(u8, function.len); 261 - @memcpy(@constCast(f.function), function); 332 + f.function = try self.arena.alloc(u8, function.len); 333 + @memcpy(@constCast(f.function), function); 262 334 263 - try frames.append(FrameWrapper{ .call_stack = f }); 264 - } else { 265 - try frames.append(FrameWrapper{ .invalid = {} }); 266 - break; 267 - } 335 + return f; 336 + } else { 337 + return error.InvalidFrame; 268 338 } 269 - 270 - sample.frames = try frames.toOwnedSlice(); 271 339 } 272 340 };