All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.evolver.basics.spring.log.MessageLogController Maven / Gradle / Ivy

package fi.evolver.basics.spring.log;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import fi.evolver.basics.spring.http.exception.HttpInternalServerErrorException;
import fi.evolver.basics.spring.http.exception.HttpNotFoundException;
import fi.evolver.basics.spring.log.LogPolicy.Policy;
import fi.evolver.basics.spring.log.entity.MessageLog;
import fi.evolver.basics.spring.log.entity.MessageLogLite;
import fi.evolver.basics.spring.log.model.MessageLogQuery;
import fi.evolver.basics.spring.util.RangeI;
import fi.evolver.basics.spring.util.RangeT;
import fi.evolver.basics.spring.util.filter.FilterValue;
import fi.evolver.utils.format.PrettyPrintUtils;
import fi.evolver.utils.format.PrettyPrintUtils.Format;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;


@RestController
@RequestMapping("/log")
public class MessageLogController {
	private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("d.M.yyyy HH:mm:ss.SSS");

	private final MessageLogLiteRepository messageLogLiteRepository;
	private final MessageLogRepository messageLogRepository;


	@Autowired
	public MessageLogController(MessageLogLiteRepository messageLogLiteRepository, MessageLogRepository messageLogRepository) {
		this.messageLogLiteRepository = messageLogLiteRepository;
		this.messageLogRepository = messageLogRepository;
	}


	@GetMapping
	@LogPolicy(Policy.NONE)
	@Operation(summary = "Fetches message log list")
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "List of message log rows"),
			@ApiResponse(responseCode = "400", description = "Invalid request parameters", content = @Content),
			@ApiResponse(responseCode = "500", description = "Failed handling request", content = @Content)
	})
	public Page list(
			@ParameterObject MessageLogQuery parameters,
			@ParameterObject @PageableDefault(size = 100, direction = Direction.DESC, sort = "startTime") Pageable page) {

		return messageLogLiteRepository.search(parameters, page);
	}

	@GetMapping(path = "/{id}")
	@LogPolicy(Policy.NONE)
	@Operation(summary = "Fetches message log by ID")
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "The message log"),
			@ApiResponse(responseCode = "400", description = "Invalid request parameters", content = @Content),
			@ApiResponse(responseCode = "404", description = "Not found", content = @Content),
			@ApiResponse(responseCode = "500", description = "Failed handling request", content = @Content)
	})
	public MessageLog get(@PathVariable long id) {
		return messageLogRepository.findById(id).orElseThrow(HttpNotFoundException::new);
	}

	@LogPolicy(Policy.NONE)
	@Operation(summary = "Fetch request contents of the message")
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "The request contents"),
			@ApiResponse(responseCode = "204", description = "No content"),
			@ApiResponse(responseCode = "400", description = "Invalid request parameters", content = @Content),
			@ApiResponse(responseCode = "404", description = "Not found", content = @Content),
			@ApiResponse(responseCode = "500", description = "Failed handling request", content = @Content)
	})
	@GetMapping(value = "/{id}/request", produces = MediaType.TEXT_PLAIN_VALUE)
	public ResponseEntity request(@PathVariable long id, @RequestParam(defaultValue = "false") boolean pretty) {
		return download(id, MessageLog::getRequestMessage, "request", pretty);
	}


	@LogPolicy(Policy.NONE)
	@Operation(summary = "Fetch response contents of the message")
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "The response contents"),
			@ApiResponse(responseCode = "204", description = "No content"),
			@ApiResponse(responseCode = "400", description = "Invalid request parameters", content = @Content),
			@ApiResponse(responseCode = "404", description = "Not found", content = @Content),
			@ApiResponse(responseCode = "500", description = "Failed handling request", content = @Content)
	})
	@GetMapping(value = "/{id}/response", produces = MediaType.TEXT_PLAIN_VALUE)
	public ResponseEntity response(@PathVariable long id, @RequestParam(defaultValue = "false") boolean pretty) {
		return download(id, MessageLog::getResponseMessage, "response", pretty);
	}


	private ResponseEntity download(long id, Function getter, String type, boolean pretty) {
		Optional messageLog = messageLogRepository.findById(id);
		if (messageLog.isEmpty())
			throw new HttpNotFoundException();

		byte[] data = getter.apply(messageLog.get());
		if (data == null)
			return new ResponseEntity<>("".getBytes(), HttpStatus.NO_CONTENT);

		Format format;
		try (Reader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data))))) {
			format = PrettyPrintUtils.inferFormat(reader);
			if (pretty && format != Format.UNKNOWN) {
				ByteArrayOutputStream bout = new ByteArrayOutputStream();
				try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(bout), StandardCharsets.UTF_8)) {
					PrettyPrintUtils.prettyPrint(reader, writer, format);
				}
				data = bout.toByteArray();
			}
		}
		catch (IOException e) {
			throw new HttpInternalServerErrorException(e);
		}

		String fileExtension = format.name().toLowerCase();
		HttpHeaders headers = new HttpHeaders();
		headers.add("Content-Encoding", "gzip");
		headers.add("Content-Disposition", String.format("attachment; filename=\"message-%s-%s%s.%s\"", messageLog.get().getId(), type, pretty ? "-pretty" : "", fileExtension));
		return new ResponseEntity<>(data, headers, HttpStatus.OK);
	}


	@LogPolicy(Policy.NONE)
	@GetMapping(path = "ui")
	public CharSequence ui(
			MessageLogQuery parameters,
			@PageableDefault(size = 100, direction = Direction.DESC, sort = "startTime") Pageable page) {

		StringBuilder builder = new StringBuilder();
		builder.append("");
		builder.append("");
		builder.append("");
		builder.append("");
		builder.append("");
		builder.append(
				"");

		builder.append("
"); builder.append("\n"); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append("\n"); builder.append(""); builder.append(""); input(builder, "v", parameters.getV()); input(builder, "srv", parameters.getSrv()); input(builder, "s", Optional.ofNullable(parameters.getS()).map(RangeT::getMin).map(DATE_TIME_FORMATTER::format), Optional.ofNullable(parameters.getS()).map(RangeT::getMax).map(DATE_TIME_FORMATTER::format)); input(builder, "d", Optional.ofNullable(parameters.getD()).map(RangeI::getMin), Optional.ofNullable(parameters.getD()).map(RangeI::getMax)); input(builder, "m", parameters.getM()); input(builder, "p", parameters.getP()); input(builder, "rqsn", parameters.getRqsn()); builder.append(""); input(builder, "rpsn", parameters.getRpsn()); input(builder, "c", parameters.getC()); input(builder, "mci", parameters.getMci()); input(builder, "rqs", Optional.ofNullable(parameters.getRqs()).map(RangeI::getMin), Optional.ofNullable(parameters.getRqs()).map(RangeI::getMax)); input(builder, "rps", Optional.ofNullable(parameters.getRps()).map(RangeI::getMin), Optional.ofNullable(parameters.getRps()).map(RangeI::getMax)); input(builder, "md", parameters.getMd()); builder.append("\n"); for (MessageLogLite messageLog: messageLogLiteRepository.search(parameters, page)) print(builder, messageLog); builder.append("
IdVersionServerStartTimeDurationMsMessageTypeProtocolRequestingSystemDirRespondingSystemStatusCodeMessageChainIdRequestSizeResponseSizeMetadata
"); builder.append("
"); builder.append(""); builder.append(""); return builder; } private static void input(StringBuilder builder, String name, List> values) { input(builder, name, values == null ? null : values.stream().map(Object::toString).collect(Collectors.joining(", "))); } private static void input(StringBuilder builder, String name, String value) { builder.append(""); } private static void input(StringBuilder builder, String name, Optional min, Optional max) { builder.append(" "); } private static String clean(T value) { return value.toString().strip().replaceAll("'", ""); } private static void print(StringBuilder builder, MessageLogLite messageLog) { builder.append(""); builder.append("").append(messageLog.getId()).append(""); builder.append("").append(messageLog.getAppVersion()).append(""); builder.append("").append(messageLog.getAppServer()).append(""); builder.append("").append(messageLog.getStartTime().format(DATE_TIME_FORMATTER)).append(""); builder.append("").append(messageLog.getDurationMs()).append(""); builder.append("").append(messageLog.getMessageType()).append(""); builder.append("").append(messageLog.getProtocol()).append(""); builder.append("").append(messageLog.getRequestingSystem()).append(""); builder.append("").append(messageLog.getDataDirection() == MessageLog.Direction.INBOUND ? "←" : "→").append(""); builder.append("").append(messageLog.getRespondingSystem()).append(""); builder.append("").append(messageLog.getStatusCode()).append(""); builder.append("") .append(messageLog.getMessageChainId()) .append(""); builder.append(""); if (messageLog.getRequestSize() > 0) builder.append(""); builder.append(messageLog.getRequestSize()); if (messageLog.getRequestSize() > 0) builder.append(""); builder.append(""); builder.append(""); if (messageLog.getResponseSize() > 0) builder.append(""); builder.append(messageLog.getResponseSize()); if (messageLog.getResponseSize() > 0) builder.append(""); builder.append(""); builder.append("
    "); messageLog.getMetadata().forEach((k, v) -> builder.append("
  • ") .append("").append(k).append("") .append(" = ") .append(v) .append("
  • ")); builder.append("
"); builder.append("\n"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy