package de.rwth.idsg.bikeman.web.rest; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.FileAppender; import com.codahale.metrics.annotation.Timed; import com.google.common.base.Optional; import de.rwth.idsg.bikeman.web.rest.dto.LoggerDTO; import lombok.extern.slf4j.Slf4j; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; /** * Controller for view and managing Log Level at runtime. */ @Slf4j @RestController @RequestMapping("/api") public class LogsResource { private Path logPath; @PostConstruct private void init() { Optional<String> optionalPath = getActiveLogFile(); if (optionalPath.isPresent()) { logPath = Paths.get(optionalPath.get()); } } @Timed @RequestMapping(value = "/logs", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List<LoggerDTO> getList() { LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); return context.getLoggerList() .stream() .map(LoggerDTO::new) .collect(Collectors.toList()); } @Timed @RequestMapping(value = "/logs", method = RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) public void changeLevel(@RequestBody LoggerDTO jsonLogger) { LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); } /** * Return the application logs */ @RequestMapping(value = "/logs/bikeman", method = RequestMethod.GET) public String log(HttpServletResponse response) { response.setContentType("text/plain"); if (logPath == null) { return "Not available. Log file does not exist."; } try { response.setContentLength((int) Files.size(logPath)); } catch (IOException e) { log.error("File size could not be calculated", e); } String fileName = "bikeman.log"; String headerKey = "Content-Disposition"; String headerValue = String.format("attachment; filename=\"%s\"", fileName); response.setHeader(headerKey, headerValue); try (PrintWriter writer = response.getWriter()) { Files.lines(logPath, StandardCharsets.UTF_8) .forEach(writer::println); } catch (IOException e) { log.error("Exception happened", e); } return null; } /** * Get the actively used log file from the underlying logging mechanism */ private Optional<String> getActiveLogFile() { Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); Iterator<Appender<ILoggingEvent>> itr = rootLogger.iteratorForAppenders(); // Iterate over the appenders while (itr.hasNext()) { Appender<ILoggingEvent> appender = itr.next(); // found a file appender if (appender instanceof FileAppender) { FileAppender<ILoggingEvent> fileAppender = (FileAppender<ILoggingEvent>) appender; return Optional.of(fileAppender.getFile()); } } // no file appender return Optional.absent(); } }