[Feature] Support structured JSON logs (Logback JSON format)#10
[Feature] Support structured JSON logs (Logback JSON format)#10MohammedGhallab wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughPR adds JSON log preprocessing to StackLens: new ChangesJSON Log Preprocessing
Sequence DiagramsequenceDiagram
participant Client as Analyzer Caller
participant Analyzer as LogAnalyzer
participant Processor as LogProcessor
participant Mapper as ObjectMapper
participant Classifier as IssueClassifier
Client->>Analyzer: analyzeFile/Stream/Text
Analyzer->>Processor: preprocessLines(raw lines)
loop for each line
Processor->>Processor: isJsonLog(line)
alt JSON detected
Processor->>Mapper: deserialize to JsonLogStructure
Mapper->>Processor: message + stack_trace
Processor->>Processor: concatenate to plain text
else not JSON
Processor->>Processor: return original line
end
end
Analyzer->>Classifier: classify(processed lines)
Classifier->>Analyzer: AnalysisResult
Analyzer->>Client: return result
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/com/stacklens/JSONlogs/LogProcessor.java`:
- Around line 19-38: parseToPlainText drops structured fields and can produce an
empty string for JSON logs without a "message"; update the JsonLogStructure
record to include `@JsonProperty`("timestamp") String timestamp and
`@JsonProperty`("level") String level, then change parseToPlainText to incorporate
timestamp and level into the output (e.g. prefix or include them when building
plainText alongside message and stackTrace) so meaningful fields are preserved
for the classifier; ensure the method returns logLine only as a last-resort
fallback (i.e., if all extracted fields are null/empty) and not when
timestamp/level exist.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0678784a-b8e3-4b0f-aee5-eb81d1fb1c2f
📒 Files selected for processing (3)
src/main/java/com/stacklens/JSONlogs/JsonLogLine.javasrc/main/java/com/stacklens/JSONlogs/LogProcessor.javasrc/main/java/com/stacklens/analyzer/LogAnalyzer.java
| JsonLogStructure jsonLog = objectMapper.readValue(logLine, JsonLogStructure.class); | ||
| StringBuilder plainText = new StringBuilder(); | ||
|
|
||
| if (jsonLog.message() != null) { | ||
| plainText.append(jsonLog.message()); | ||
| } | ||
| if (jsonLog.stackTrace() != null && !jsonLog.stackTrace().isEmpty()) { | ||
| plainText.append("\n").append(jsonLog.stackTrace()); | ||
| } | ||
| return plainText.toString(); | ||
| } catch (Exception e) { | ||
| return logLine; | ||
| } | ||
| } | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| record JsonLogStructure( | ||
| @JsonProperty("message") String message, | ||
| @JsonProperty("stack_trace") String stackTrace | ||
| ) {} |
There was a problem hiding this comment.
Preserve structured fields during normalization to avoid lossy classifier input.
parseToPlainText currently drops timestamp and level, and may return an empty string for valid JSON logs that lack message. Since preprocessing is now always applied before classification, this silently removes useful signal from the pipeline.
Suggested fix
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
@@
public String parseToPlainText(String logLine) {
try {
- JsonLogStructure jsonLog = objectMapper.readValue(logLine, JsonLogStructure.class);
+ JsonLogLine jsonLog = objectMapper.readValue(logLine, JsonLogLine.class);
StringBuilder plainText = new StringBuilder();
-
- if (jsonLog.message() != null) {
- plainText.append(jsonLog.message());
+
+ if (jsonLog.getTimestamp() != null && !jsonLog.getTimestamp().isBlank()) {
+ plainText.append(jsonLog.getTimestamp());
}
- if (jsonLog.stackTrace() != null && !jsonLog.stackTrace().isEmpty()) {
- plainText.append("\n").append(jsonLog.stackTrace());
+ if (jsonLog.getLevel() != null && !jsonLog.getLevel().isBlank()) {
+ if (plainText.length() > 0) plainText.append(" ");
+ plainText.append(jsonLog.getLevel());
}
- return plainText.toString();
+ if (jsonLog.getMessage() != null && !jsonLog.getMessage().isBlank()) {
+ if (plainText.length() > 0) plainText.append(" ");
+ plainText.append(jsonLog.getMessage());
+ }
+ if (jsonLog.getStackTrace() != null && !jsonLog.getStackTrace().isBlank()) {
+ if (plainText.length() > 0) plainText.append("\n");
+ plainText.append(jsonLog.getStackTrace());
+ }
+ return plainText.length() > 0 ? plainText.toString() : logLine;
} catch (Exception e) {
return logLine;
}
}
-
- `@JsonIgnoreProperties`(ignoreUnknown = true)
- record JsonLogStructure(
- `@JsonProperty`("message") String message,
- `@JsonProperty`("stack_trace") String stackTrace
- ) {}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/stacklens/JSONlogs/LogProcessor.java` around lines 19 - 38,
parseToPlainText drops structured fields and can produce an empty string for
JSON logs without a "message"; update the JsonLogStructure record to include
`@JsonProperty`("timestamp") String timestamp and `@JsonProperty`("level") String
level, then change parseToPlainText to incorporate timestamp and level into the
output (e.g. prefix or include them when building plainText alongside message
and stackTrace) so meaningful fields are preserved for the classifier; ensure
the method returns logLine only as a last-resort fallback (i.e., if all
extracted fields are null/empty) and not when timestamp/level exist.
Summary by CodeRabbit