001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.log.render.json; 020 021import com.fasterxml.jackson.annotation.JsonInclude; 022import com.fasterxml.jackson.core.JsonProcessingException; 023import com.fasterxml.jackson.databind.ObjectMapper; 024import com.fasterxml.jackson.databind.module.SimpleModule; 025import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 026import org.jpos.log.AuditLogEvent; 027 028import org.jpos.log.LogRenderer; 029import org.jpos.log.evt.LogEvt; 030import org.jpos.log.evt.LogMessage; 031import org.jpos.log.evt.ThrowableAuditLogEvent; 032import org.jpos.log.render.ThrowableSerializer; 033import org.jpos.util.LogEvent; 034import org.jpos.util.Loggeable; 035 036import java.io.ByteArrayOutputStream; 037import java.io.PrintStream; 038import java.time.Duration; 039import java.util.List; 040 041public final class LogEventJsonLogRenderer implements LogRenderer<LogEvent> { 042 private final ObjectMapper mapper = new ObjectMapper(); 043 044 public LogEventJsonLogRenderer() { 045 mapper.registerModule(new JavaTimeModule()); 046 mapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 047 // mapper.enable(SerializationFeature.INDENT_OUTPUT); 048 mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 049 SimpleModule module = new SimpleModule(); 050 module.addSerializer(Throwable.class, new ThrowableSerializer()); 051 mapper.registerModule(module); 052 } 053 054 @Override 055 public void render(LogEvent evt, PrintStream ps, String indent) { 056 List<AuditLogEvent> events = evt.getPayLoad() 057 .stream() 058 .map (obj -> switch (obj) { 059 case AuditLogEvent ale -> ale; 060 case Throwable t -> new ThrowableAuditLogEvent(t); 061 default -> new LogMessage(dump(obj)); 062 }).toList(); 063 064 long elapsed = Duration.between(evt.getCreatedAt(), evt.getDumpedAt()).toMillis(); 065 LogEvt ev = new LogEvt ( 066 evt.getDumpedAt(), 067 evt.getTraceId(), 068 evt.getRealm(), 069 evt.getTag(), 070 elapsed == 0L ? null : elapsed, 071 events 072 ); 073 try { 074 ps.println (mapper.writeValueAsString(ev)); 075 } catch (JsonProcessingException e) { 076 throw new RuntimeException (e); 077 } 078 } 079 public Class<?> clazz() { 080 return LogEvent.class; 081 } 082 public Type type() { 083 return Type.JSON; 084 } 085 086 private String dump (Object obj) { 087 if (obj instanceof Loggeable loggeable) { 088 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 089 PrintStream ps = new PrintStream(baos); 090 loggeable.dump(ps, ""); 091 return baos.toString(); 092 } 093 return obj.getClass() + ":" + obj; 094 } 095}