use @Slf4j (+logback) for logging instead of System.out/err.println (#165)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/165 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
		| @@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.config; | ||||
|  | ||||
| import io.micrometer.core.annotation.Timed; | ||||
| import lombok.SneakyThrows; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.beans.factory.annotation.Value; | ||||
| import org.springframework.security.authentication.BadCredentialsException; | ||||
| import org.springframework.util.LinkedMultiValueMap; | ||||
| @@ -14,6 +15,8 @@ import javax.xml.parsers.DocumentBuilderFactory; | ||||
| import javax.xml.parsers.ParserConfigurationException; | ||||
| import java.io.IOException; | ||||
|  | ||||
| // HOWTO add logger | ||||
| @Slf4j | ||||
| public class RealCasAuthenticator implements CasAuthenticator { | ||||
|  | ||||
|     @Value("${hsadminng.cas.server}") | ||||
| @@ -32,7 +35,8 @@ public class RealCasAuthenticator implements CasAuthenticator { | ||||
|                 ? fetchServiceTicket(ticket) | ||||
|                 : ticket; | ||||
|         final var userName = extractUserName(verifyServiceTicket(serviceTicket)); | ||||
|         System.err.println("CAS-user: " + userName); | ||||
|         // HOWTO log some message for a certain log level (trace, debug, info, warn, error) | ||||
|         log.debug("CAS-user: {}", userName); | ||||
|         return userName; | ||||
|     } | ||||
|  | ||||
| @@ -65,9 +69,7 @@ public class RealCasAuthenticator implements CasAuthenticator { | ||||
|     private String extractUserName(final Document verification) { | ||||
|  | ||||
|         if (verification.getElementsByTagName("cas:authenticationSuccess").getLength() == 0) { | ||||
|             System.err.println("CAS service ticket could not be validated"); | ||||
|             System.err.println(verification); | ||||
|             throwBadCredentialsException("CAS service ticket could not be validated"); | ||||
|             throwBadCredentialsException("CAS service ticket could not be verified"); | ||||
|         } | ||||
|         return verification.getElementsByTagName("cas:user").item(0).getTextContent(); | ||||
|     } | ||||
|   | ||||
| @@ -28,6 +28,7 @@ import java.util.regex.Pattern; | ||||
| import static net.hostsharing.hsadminng.errors.CustomErrorResponse.*; | ||||
|  | ||||
| @ControllerAdvice | ||||
| // HOWTO handle exceptions to produce specific http error codes and sensible error messages | ||||
| public class RestResponseEntityExceptionHandler | ||||
|         extends ResponseEntityExceptionHandler { | ||||
|  | ||||
|   | ||||
| @@ -121,10 +121,4 @@ public final class HashGenerator { | ||||
|         } | ||||
|         return withSalt(stringBuilder.toString()); | ||||
|     } | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         System.out.println( | ||||
|             HashGenerator.using(Algorithm.LINUX_YESCRYPT).withRandomSalt().hash("my plaintext domain transfer passphrase") | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -125,10 +125,4 @@ public class Dns { | ||||
|             return Result.fromException(exception); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         final var result = new Dns("example.org").fetchRecordsOfType("TXT"); | ||||
|         System.out.println(result); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1261,15 +1261,11 @@ public class RbacSpec { | ||||
|                         m -> isStatic(m.getModifiers()) && m.getName().equals("main") | ||||
|                 ) | ||||
|                 .findFirst() | ||||
|                 .orElse(null); | ||||
|         if (mainMethod != null) { | ||||
|             try { | ||||
|                 mainMethod.invoke(null, new Object[] { null }); | ||||
|             } catch (IllegalAccessException | InvocationTargetException e) { | ||||
|                 throw new RuntimeException(e); | ||||
|             } | ||||
|         } else { | ||||
|             System.err.println("WARNING: no main method in: " + c.getName() + " => no RBAC rules generated"); | ||||
|                 .orElseThrow(() -> new RuntimeException("no main method in: " + c.getName() + " => cannot generate RBAC rules")); | ||||
|         try { | ||||
|             mainMethod.invoke(null, new Object[] { null }); | ||||
|         } catch (IllegalAccessException | InvocationTargetException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -202,6 +202,5 @@ public class RbacViewMermaidFlowchartGenerator { | ||||
|                     .replace("%{flowchart}", flowchart.toString()) | ||||
|                     .replace("%{case}", forCase == null ? "" : " " + forCase), | ||||
|                 StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); | ||||
|         System.out.println("Markdown-File: " + path.toAbsolutePath()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -49,6 +49,5 @@ public class RbacViewPostgresGenerator { | ||||
|                 toString(), | ||||
|                 StandardOpenOption.CREATE, | ||||
|                 StandardOpenOption.TRUNCATE_EXISTING); | ||||
|         System.out.println(outputPath.toAbsolutePath()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -358,9 +358,6 @@ class RolesGrantsAndPermissionsGenerator { | ||||
|     } | ||||
|  | ||||
|     private String roleRef(final PostgresTriggerReference rootRefVar, final RbacSpec.RbacRoleDefinition roleDef) { | ||||
|         if (roleDef == null) { | ||||
|             System.out.println("null"); | ||||
|         } | ||||
|         if (roleDef.getEntityAlias().isGlobal()) { | ||||
|             return "rbac.global_ADMIN()"; | ||||
|         } | ||||
|   | ||||
| @@ -68,8 +68,10 @@ metrics: | ||||
|                 server: | ||||
|                     requests: true | ||||
|  | ||||
| # HOWTO set logging-levels for certain Java packages (trace, debug, info, warn, error) | ||||
| logging: | ||||
|     level: | ||||
|         org: | ||||
|             springframework: | ||||
|                 security: TRACE | ||||
|         org.springframework.security: info | ||||
| # HOWTO configure logging, e.g. logging to a separate file, see: | ||||
| #   https://docs.spring.io/spring-boot/reference/features/logging.html | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,16 @@ | ||||
| package net.hostsharing.hsadminng.config; | ||||
|  | ||||
| import com.github.tomakehurst.wiremock.WireMockServer; | ||||
| import net.hostsharing.hsadminng.test.LogbackLogPattern; | ||||
| import org.junit.jupiter.api.Tag; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.api.extension.ExtendWith; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.beans.factory.annotation.Value; | ||||
| import org.springframework.boot.logging.LogLevel; | ||||
| import org.springframework.boot.test.context.SpringBootTest; | ||||
| import org.springframework.boot.test.system.CapturedOutput; | ||||
| import org.springframework.boot.test.system.OutputCaptureExtension; | ||||
| import org.springframework.boot.test.web.client.TestRestTemplate; | ||||
| import org.springframework.http.HttpEntity; | ||||
| import org.springframework.http.HttpMethod; | ||||
| @@ -13,15 +18,23 @@ import org.springframework.http.HttpStatus; | ||||
| import org.springframework.test.context.ActiveProfiles; | ||||
| import org.springframework.test.context.TestPropertySource; | ||||
|  | ||||
| import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; | ||||
| import static com.github.tomakehurst.wiremock.client.WireMock.get; | ||||
| import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; | ||||
| import static net.hostsharing.hsadminng.config.HttpHeadersBuilder.headers; | ||||
| import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric; | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static com.github.tomakehurst.wiremock.client.WireMock.*; | ||||
|  | ||||
| @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | ||||
| @TestPropertySource(properties = {"server.port=0", "hsadminng.cas.server=http://localhost:8088"}) | ||||
| @TestPropertySource(properties = { | ||||
|         "server.port=0", | ||||
|         "hsadminng.cas.server=http://localhost:8088", | ||||
|  | ||||
|         "logging.level.root=DEBUG" | ||||
| }) | ||||
| @ActiveProfiles({"wiremock", "realCasAuthenticator"}) // IMPORTANT: To test prod config, do NOT use test profile! | ||||
| @Tag("generalIntegrationTest") | ||||
| @ExtendWith(OutputCaptureExtension.class) | ||||
| class CasAuthenticationFilterIntegrationTest { | ||||
|  | ||||
|     @Value("${local.server.port}") | ||||
| @@ -37,7 +50,7 @@ class CasAuthenticationFilterIntegrationTest { | ||||
|     private WireMockServer wireMockServer; | ||||
|  | ||||
|     @Test | ||||
|     public void shouldAcceptRequestWithValidCasTicket() { | ||||
|     public void shouldAcceptRequestWithValidCasTicket(final CapturedOutput capturedOutput) { | ||||
|         // given | ||||
|         final var username = "test-user-" + randomAlphanumeric(4); | ||||
|         wireMockServer.stubFor(get(urlEqualTo("/cas/p3/serviceValidate?service=" + serviceUrl + "&ticket=ST-valid")) | ||||
| @@ -63,6 +76,9 @@ class CasAuthenticationFilterIntegrationTest { | ||||
|         // then | ||||
|         assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); | ||||
|         assertThat(result.getBody()).isEqualTo("pong " + username + "\n"); | ||||
|         // HOWTO assert log messages | ||||
|         assertThat(capturedOutput.getOut()).containsPattern( | ||||
|                 LogbackLogPattern.of(LogLevel.DEBUG, RealCasAuthenticator.class, "CAS-user: " + username)); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|   | ||||
| @@ -39,8 +39,8 @@ class RestResponseEntityExceptionHandlerUnitTest { | ||||
|         final var errorResponse = exceptionHandler.handleConflict(givenException, givenWebRequest); | ||||
|  | ||||
|         // then | ||||
|         assertThat(errorResponse.getBody().getStatusCode()).isEqualTo(409); | ||||
|         assertThat(errorResponse.getBody().getMessage()).isEqualTo("ERROR: [409] First Line"); | ||||
|         assertThat(errorResponse.getBody()).extracting(CustomErrorResponse::getStatusCode).isEqualTo(409); | ||||
|         assertThat(errorResponse.getBody()).extracting(CustomErrorResponse::getMessage).isEqualTo("ERROR: [409] First Line"); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|   | ||||
| @@ -0,0 +1,21 @@ | ||||
| package net.hostsharing.hsadminng.test; | ||||
|  | ||||
| import ch.qos.logback.classic.pattern.TargetLengthBasedClassNameAbbreviator; | ||||
| import org.springframework.boot.logging.LogLevel; | ||||
|  | ||||
| public class LogbackLogPattern { | ||||
|  | ||||
|     private static final int LOGBACK_MAX_CLASSNAME_LENGTH = 36; | ||||
|  | ||||
|     /** | ||||
|      * @return a regular expression for a log message | ||||
|      */ | ||||
|     public static CharSequence of( | ||||
|             final LogLevel logLevel, | ||||
|             final Class<?> loggingClass, | ||||
|             final String message) { | ||||
|         final var abbreviator = new TargetLengthBasedClassNameAbbreviator(LOGBACK_MAX_CLASSNAME_LENGTH); | ||||
|         final var shortenedClassName = abbreviator.abbreviate(loggingClass.getName()); | ||||
|         return logLevel + " [0-9]+ .* " + shortenedClassName +  " *: " + message; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user