package io.mangoo.admin; import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.LongAdder; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import com.google.inject.Inject; import io.mangoo.annotations.FilterWith; import io.mangoo.core.Application; import io.mangoo.crypto.Crypto; import io.mangoo.enums.Required; import io.mangoo.enums.Template; import io.mangoo.exceptions.MangooSchedulerException; import io.mangoo.models.Job; import io.mangoo.models.Metrics; import io.mangoo.routing.Response; import io.mangoo.routing.Route; import io.mangoo.routing.Router; import io.mangoo.routing.bindings.Request; import io.mangoo.scheduler.Scheduler; import io.mangoo.utils.BootstrapUtils; import io.mangoo.utils.CodecUtils; /** * Controller class for administrative URLs * * @author svenkubiak * */ @FilterWith(AdminFilter.class) public class AdminController { private static final org.apache.logging.log4j.Logger LOG = LogManager.getLogger(AdminController.class); private static final String SCHEDULER = "scheduler"; private static final String METRICS = "metrics"; //NOSONAR private static final String ROUTES = "routes"; //NOSONAR private static final String JOBS = "jobs"; private static final String LOGGER = "logger"; private static final String TOOLS = "tools"; private static final String SPACE = "space"; private static final String VERSION = "version"; private final Scheduler scheduler; //NOSONAR private final Crypto crypto; //NOSONAR @Inject public AdminController(Scheduler scheduler, Crypto crypto) { this.scheduler = Objects.requireNonNull(scheduler, Required.SCHEDULER.toString()); this.crypto = Objects.requireNonNull(crypto, Required.CRYPTO.toString()); } public Response index() { Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long allocatedMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); Instant instant = Application.getStart().atZone(ZoneId.systemDefault()).toInstant(); return Response.withOk() .andContent(VERSION, BootstrapUtils.getVersion()) .andContent(SPACE, null) .andContent("uptime", Date.from(instant)) .andContent("started", Application.getStart()) .andContent("maxMemory", FileUtils.byteCountToDisplaySize(maxMemory)) .andContent("allocatedMemory", FileUtils.byteCountToDisplaySize(allocatedMemory)) .andContent("freeMemory", FileUtils.byteCountToDisplaySize(freeMemory)) .andContent("totalFreeMemory", FileUtils.byteCountToDisplaySize(freeMemory + (maxMemory - allocatedMemory))) .andTemplate(Template.DEFAULT.adminPath()); } public Response execute(String name) { try { this.scheduler.executeJob(name); } catch (MangooSchedulerException e) { LOG.error("Failed to execute job with name: " + name, e); } return Response.withRedirect("/@admin/scheduler"); } public Response state(String name) { try { this.scheduler.changeState(name); } catch (MangooSchedulerException e) { LOG.error("Failed to change the state of job with name: " + name, e); } return Response.withRedirect("/@admin/scheduler"); } public Response routes() { Set<Route> routes = Router.getRoutes() .stream() .filter(route -> !route.getUrl().contains("@admin")) .collect(Collectors.toSet()); return Response.withOk() .andContent(SPACE, ROUTES) .andContent(VERSION, BootstrapUtils.getVersion()) .andContent(ROUTES, routes) .andTemplate(Template.DEFAULT.routesPath()); } public Response tools() { return Response.withOk() .andContent(SPACE, TOOLS) .andContent(VERSION, BootstrapUtils.getVersion()) .andTemplate(Template.DEFAULT.toolsPath()); } public Response logger() { LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); return Response.withOk() .andContent(SPACE, LOGGER) .andContent(VERSION, BootstrapUtils.getVersion()) .andContent("loggers", loggerContext.getLoggers()) .andTemplate(Template.DEFAULT.loggerPath()); } public Response loggerajax(Request request) { Map<String, Object> body = request.getBodyAsJsonMap(); if (body != null && body.size() > 0) { String clazz = body.get("class").toString(); String level = body.get("level").toString(); if (StringUtils.isNotBlank(clazz) && StringUtils.isNotBlank(level)) { LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); for (Logger logger : loggerContext.getLoggers()) { //NOSONAR if (clazz.equals(logger.getName())) { logger.setLevel(Level.getLevel(level)); break; } } } } return Response.withOk().andEmptyBody(); } public Response toolsajax(Request request) { Map<String, Object> body = request.getBodyAsJsonMap(); String value = ""; if (body != null && body.size() > 0) { String function = body.get("function").toString(); String cleartext = body.get("cleartext").toString(); String key = body.get("key").toString(); if (("hash").equalsIgnoreCase(function)) { value = CodecUtils.hexJBcrypt(cleartext); } else if (("encrypt").equalsIgnoreCase(function)) { if (StringUtils.isNotBlank(key)) { value = this.crypto.encrypt(cleartext, key); } else { value = this.crypto.encrypt(cleartext); } } } return Response.withOk() .andJsonBody(value); } public Response metrics() { Metrics metrics = Application.getInstance(Metrics.class); long totalRequests = 0; long errorRequests = 0; double errorRate = 0; for (Entry<Integer, LongAdder> entry : metrics.getMetrics().entrySet()) { if (String.valueOf(entry.getKey()).charAt(0) == '5') { errorRequests = errorRequests + entry.getValue().longValue(); } totalRequests = totalRequests + entry.getValue().longValue(); } if (errorRequests > 0) { errorRate = totalRequests / (double) errorRequests; } return Response.withOk() .andContent(SPACE, METRICS) .andContent(VERSION, BootstrapUtils.getVersion()) .andContent(METRICS, metrics.getMetrics()) .andContent("totalRequests", totalRequests) .andContent("minRequestTime", metrics.getMinRequestTime()) .andContent("avgRequestTime", metrics.getAvgRequestTime()) .andContent("maxRequestTime", metrics.getMaxRequestTime()) .andContent("errorRate", errorRate) .andTemplate(Template.DEFAULT.metricsPath()); } public Response scheduler() { List<Job> jobs = new ArrayList<>(); if (this.scheduler.isInitialize()) { try { jobs = this.scheduler.getAllJobs(); } catch (MangooSchedulerException e) { LOG.error("Failed to retrieve jobs from scheduler", e); } } return Response.withOk() .andContent(SPACE, SCHEDULER) .andContent(VERSION, BootstrapUtils.getVersion()) .andContent(JOBS, jobs) .andTemplate(Template.DEFAULT.schedulerPath()); } }