ConsoleAppender implements LogAppender { String message(ActionLogMessage log) { var format = new DecimalFormat(); var builder = new StringBuilder(512); builder.append(DateTimeFormatter.ISO_INSTANT.format(log.date)) .append(LOG_SPLITTER).append(log.result) .append(LOG_SPLITTER).append("elapsed=").append(format.format(log.elapsed.longValue())) .append(LOG_SPLITTER).append("id=").append(log.id) .append(LOG_SPLITTER).append("action=").append(log.action); if (log.correlationIds != null) { builder.append(LOG_SPLITTER).append("correlation_id="); appendList(builder, log.correlationIds); } String errorCode = log.errorCode; if (errorCode != null) { builder.append(LOG_SPLITTER).append("error_code=").append(errorCode) .append(LOG_SPLITTER).append("error_message=").append(filterLineSeparator(log.errorMessage)); } for (Map.Entry<String, List<String>> entry : log.context.entrySet()) { String key = entry.getKey(); List<String> values = entry.getValue(); for (String value : values) { builder.append(LOG_SPLITTER).append(key).append('=').append(filterLineSeparator(value)); } } if (log.clients != null) { builder.append(LOG_SPLITTER).append("client="); appendList(builder, log.clients); } if (log.refIds != null) { builder.append(LOG_SPLITTER).append("ref_id="); appendList(builder, log.refIds); } for (Map.Entry<String, Double> entry : log.stats.entrySet()) { builder.append(LOG_SPLITTER).append(entry.getKey()).append('=').append(format.format(entry.getValue())); } for (Map.Entry<String, PerformanceStatMessage> entry : log.performanceStats.entrySet()) { String key = entry.getKey(); PerformanceStatMessage stat = entry.getValue(); builder.append(LOG_SPLITTER).append(key).append("_count=").append(stat.count); if (stat.readEntries != null) builder.append(LOG_SPLITTER).append(key).append("_reads=").append(stat.readEntries); if (stat.writeEntries != null) builder.append(LOG_SPLITTER).append(key).append("_writes=").append(stat.writeEntries); builder.append(LOG_SPLITTER).append(key).append("_elapsed=").append(format.format(stat.totalElapsed)); } return builder.toString(); }  @Override void append(ActionLogMessage message); @Override void append(StatMessage message);  }
@Test void actionLogMessage() { var action = new ActionLogMessage(); action.date = Instant.now(); action.result = "OK"; action.action = "action"; action.correlationIds = List.of("refId1", "refId2"); action.context = Map.of("context", List.of("value")); action.performanceStats = Map.of("db", perf(100, 1, 0), "redis", perf(120, 0, 1)); action.clients = List.of("service"); action.refIds = List.of("refId3"); action.stats = Map.of("cpu_time", 100.0); action.elapsed = 100L; String message = appender.message(action); assertThat(message) .contains("| OK |") .contains("| elapsed=100 |") .contains("| correlation_id=refId1,refId2 |") .contains("| action=action |") .contains("| context=value |") .contains("| client=service |") .contains("| ref_id=refId3 |") .contains("| cpu_time=100 |") .contains("| db_count=1 | db_reads=1 | db_writes=0 | db_elapsed=100") .contains("| redis_count=1 | redis_reads=0 | redis_writes=1 | redis_elapsed=120"); }
@Test void statMessage() { var stat = new StatMessage(); stat.date = Instant.now(); stat.stats = Map.of("thread_count", 10.0, "cpu_usage", 0.01); stat.info = Map.of("info", "text"); String message = appender.message(stat); assertThat(message) .contains("| thread_count=10") .contains("| cpu_usage=0.01") .contains("| info=text"); }