LoggerController.java

/*
 * Copyright 2022 Global Crop Diversity Trust
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.genesys.server.api.admin.v1;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.genesys.server.api.ApiBaseController;
import org.genesys.server.api.Pagination;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController("loggerAPIV1")
@RequestMapping(LoggerController.CONTROLLER_URL)
@PreAuthorize("hasRole('ADMINISTRATOR')")
public class LoggerController {

	/** The Constant CONTROLLER_URL. */
	public static final String CONTROLLER_URL = ApiBaseController.APIv1_BASE + "/admin/logger";

	@GetMapping(value = "", produces = { MediaType.APPLICATION_JSON_VALUE })
	public PageImpl<LoggerResponse> getLoggerPage(@ParameterObject final Pagination page) {

		List<LoggerResponse> allLoggers = getAllLoggers();
		var pageRequest = page.toPageRequest(100, 20);
		
		int pageSize = pageRequest.getPageSize();
		int pageNumber = pageRequest.getPageNumber();
		
		int firstElement = ((pageNumber + 1) * pageSize) - pageSize;
		int lastElement = Math.min((pageNumber + 1) * pageSize, allLoggers.size());

		// copy part of array
		List<LoggerResponse> loggers = new ArrayList<>(allLoggers.subList(firstElement, lastElement));

		return new PageImpl<>(loggers, pageRequest, allLoggers.size());
	}

	@PostMapping(value = "{loggerName}/changeLoger/{loggerLevel}", produces = { MediaType.APPLICATION_JSON_VALUE })
	public LoggerResponse changeLogger(@PathVariable(value = "loggerLevel") String loggerLevel, @PathVariable(value = "loggerName") String loggerName) {
		LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
		Configuration config = loggerContext.getConfiguration();

		LoggerConfig loggerConfig;

		if (loggerName == null || "root".equalsIgnoreCase(loggerName)) {
			loggerConfig = config.getRootLogger();
		} else {
			loggerConfig = config.getLoggerConfig(loggerName);
		}

		if (loggerConfig != null) {
			loggerConfig.setLevel(loggerLevel == null ? null : Level.toLevel(loggerLevel));
			loggerContext.updateLoggers();
			List<String> appenders = new ArrayList<>(loggerContext.getConfiguration().getAppenders().keySet());
			return new LoggerResponse(loggerConfig.getName(), loggerConfig.getLevel().toString(), appenders);
		} else {
			return null;
		}
	}

	private List<LoggerResponse> getAllLoggers() {

		List<LoggerResponse> loggers = new ArrayList<>();

		LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
		Configuration config = loggerContext.getConfiguration();
		List<String> appenders = new ArrayList<>(loggerContext.getConfiguration().getAppenders().keySet());

		config.getLoggers().values().forEach(loggerConfig -> {
			LoggerResponse loggerResponse = new LoggerResponse();
			loggerResponse.loggerName = loggerConfig.getName();
			loggerResponse.loggerLevel = loggerConfig.getLevel().toString();
			loggerResponse.appenders = appenders;
			loggers.add(loggerResponse);
		});

		loggers.sort((o1, o2) -> {
			// root logger is on the top

			if (StringUtils.isEmpty(o1.loggerName)) {
				return -1;
			} else if (StringUtils.isEmpty(o1.loggerName)) {
				return 1;
			}
			// otherwise sort by name
			return o1.loggerName.compareTo(o2.loggerName);
		});

		return loggers;
	}

	@PostMapping(value = "/addLoger", produces = { MediaType.APPLICATION_JSON_VALUE })
	public LoggerResponse addLogger(@RequestParam(value = "nameNewLogger") String nameNewLogger, @RequestParam("loggerLevel") String loggerLevel) {
		LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
		Configuration config = loggerContext.getConfiguration();
		Level level = Level.toLevel(loggerLevel);

		LoggerConfig loggerConfig = new LoggerConfig(nameNewLogger, level, false);
		Appender appender = config.getRootLogger().getAppenders().values().stream().findFirst().orElse(null);
		loggerConfig.addAppender(appender, level, null);
		config.addLogger(nameNewLogger, loggerConfig);

		loggerContext.updateLoggers();

		List<String> appenders = new ArrayList<>(loggerContext.getConfiguration().getAppenders().keySet());

		return new LoggerResponse(loggerConfig.getName(), loggerConfig.getLevel().toString(), appenders);
	}

	public static class LoggerResponse {
		public String loggerName;
		public String loggerLevel;
		public List<String> appenders;

		public LoggerResponse() {
		}

		public LoggerResponse(String loggerName, String loggerLevel, List<String> appenders) {
			this.loggerName = loggerName;
			this.loggerLevel = loggerLevel;
			this.appenders = appenders;
		}
	}
}