diff --git a/.gitignore b/.gitignore
index 176230d5..8082ba68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,88 +1,89 @@
-# ending with / = directory, starting with / = absolute (from .gitignore location)
-# e.g. target/ is target directory ignored anywhere in the tree, /.idea/ is only in the root
-# to override generic rule, use !, e.g. !/some/module/build/ would not be ignored
-
-# Java/Maven build tool files
-target/
-build/
-test-output/
-dependency-reduced-pom.xml
-apache-maven-3.9.9/
-apache-maven-3.9.9-bin.zip
-.claude
-
-# Node modules
-node_modules/
-
-# IDEA files
-/.idea/
-/.run/
-*.iml
-
-# Eclipse files
-.project
-.classpath
-.settings
-.settings/
-
-# Other IDE files
-.c9/
-*.launch
-*.sublime-workspace
-
-# Visual Studio Code
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
-.history/*
-
-# JRebel files
-rebel.xml
-
-# jenv related
-.java-version
-
-# NetBeans files
-/nb-configuration.xml
-/nbactions.xml
-
-# Backup, log and other files
-*~
-*.log
-*.versionsBackup
-.DS_Store
-Thumbs.db
-_mess
-.checkstyle
-
-# midPoint Studio temporary files
-/scratches/
-
-# Angular / Frontend
-frontend/node_modules/
-frontend/dist/
-frontend/.angular/
-frontend/package-lock.json
-angular-frontend/node_modules/
-angular-frontend/dist/
-angular-frontend/tmp/
-angular-frontend/out-tsc/
-angular-frontend/bazel-out/
-angular-frontend/.angular/
-angular-frontend/.sass-cache/
-angular-frontend/connect.lock
-angular-frontend/coverage/
-angular-frontend/libpeerconnection.log
-angular-frontend/testem.log
-angular-frontend/typings/
-angular-frontend/__screenshots__/
-
-# Logs
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# Docker secrets
-docker/secrets/
+# ending with / = directory, starting with / = absolute (from .gitignore location)
+# e.g. target/ is target directory ignored anywhere in the tree, /.idea/ is only in the root
+# to override generic rule, use !, e.g. !/some/module/build/ would not be ignored
+
+# Java/Maven build tool files
+target/
+build/
+test-output/
+dependency-reduced-pom.xml
+apache-maven-3.9.9/
+apache-maven-3.9.9-bin.zip
+.claude
+
+# Node modules
+node_modules/
+
+# IDEA files
+/.idea/
+/.run/
+*.iml
+
+# Eclipse files
+.project
+.classpath
+.settings
+.settings/
+
+# Other IDE files
+.c9/
+*.launch
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# JRebel files
+rebel.xml
+
+# jenv related
+.java-version
+
+# NetBeans files
+/nb-configuration.xml
+/nbactions.xml
+
+# Backup, log and other files
+*~
+*.log
+logs/
+*.versionsBackup
+.DS_Store
+Thumbs.db
+_mess
+.checkstyle
+
+# midPoint Studio temporary files
+/scratches/
+
+# Angular / Frontend
+frontend/node_modules/
+frontend/dist/
+frontend/.angular/
+frontend/package-lock.json
+angular-frontend/node_modules/
+angular-frontend/dist/
+angular-frontend/tmp/
+angular-frontend/out-tsc/
+angular-frontend/bazel-out/
+angular-frontend/.angular/
+angular-frontend/.sass-cache/
+angular-frontend/connect.lock
+angular-frontend/coverage/
+angular-frontend/libpeerconnection.log
+angular-frontend/testem.log
+angular-frontend/typings/
+angular-frontend/__screenshots__/
+
+# Logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Docker secrets
+docker/secrets/
diff --git a/pom.xml b/pom.xml
index 4207f492..f2776249 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,10 @@
+
+ GitHub
+ https://github.com/Evolveum/integration-catalog/issues
+
21
@@ -109,11 +113,56 @@
+
+
+
+ src/main/resources
+ true
+
+ banner.txt
+
+
+
+ src/main/resources
+ false
+
+ banner.txt
+
+
+
org.springframework.boot
spring-boot-maven-plugin
+
+
+ io.github.git-commit-id
+ git-commit-id-maven-plugin
+ 9.0.1
+
+
+ get-git-info
+ initialize
+
+ revision
+
+
+
+
+ false
+ true
+
+
diff --git a/src/main/java/com/evolveum/midpoint/integration/catalog/IntegrationCatalogApplication.java b/src/main/java/com/evolveum/midpoint/integration/catalog/IntegrationCatalogApplication.java
index 9549ad92..3d5e9f96 100644
--- a/src/main/java/com/evolveum/midpoint/integration/catalog/IntegrationCatalogApplication.java
+++ b/src/main/java/com/evolveum/midpoint/integration/catalog/IntegrationCatalogApplication.java
@@ -27,6 +27,11 @@ public class IntegrationCatalogApplication {
= (Logger) LoggerFactory.getLogger(IntegrationCatalogApplication.class);
public static void main(String[] args) {
+ // Guarantee the banner is the first thing logged. Spring Boot's background
+ // pre-initializer warms up classes (e.g. Hibernate Validator) on a separate
+ // thread and can log before the banner is printed; disabling it keeps the
+ // banner on top. Must be set before SpringApplication.run(...).
+ System.setProperty("spring.backgroundpreinitializer.ignore", "true");
SpringApplication.run(IntegrationCatalogApplication.class, args);
}
diff --git a/src/main/java/com/evolveum/midpoint/integration/catalog/configuration/ConsoleLoggingToggle.java b/src/main/java/com/evolveum/midpoint/integration/catalog/configuration/ConsoleLoggingToggle.java
new file mode 100644
index 00000000..a4639fc8
--- /dev/null
+++ b/src/main/java/com/evolveum/midpoint/integration/catalog/configuration/ConsoleLoggingToggle.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010-2025 Evolveum and contributors
+ *
+ * Licensed under the EUPL-1.2 or later.
+ */
+
+package com.evolveum.midpoint.integration.catalog.configuration;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.filter.ThresholdFilter;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * Keeps the terminal quiet once the application is running, without losing warnings/errors.
+ *
+ * During startup the console ("stdout") appender has no level filter, so all initialization
+ * logs are visible in the terminal (and saved to file). Once the application is fully
+ * initialized ({@link ApplicationReadyEvent}), a {@link ThresholdFilter} set to {@code WARN}
+ * is added to the console appender, so from then on only {@code WARN}/{@code ERROR} flash in
+ * the terminal while {@code INFO}/{@code DEBUG} keep going to the file only. The file appender
+ * is never touched, so the log file continues to capture everything.
+ */
+@Component
+public class ConsoleLoggingToggle {
+
+ private static final Logger LOG = (Logger) LoggerFactory.getLogger(ConsoleLoggingToggle.class);
+
+ /** Must match the appender name in log4j.xml. */
+ private static final String CONSOLE_APPENDER_NAME = "stdout";
+
+ /** Minimum level allowed to reach the terminal after startup. */
+ private static final String RUNTIME_CONSOLE_THRESHOLD = "WARN";
+
+ @EventListener(ApplicationReadyEvent.class)
+ public void raiseConsoleThresholdAfterStartup() {
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
+ Appender consoleAppender = rootLogger.getAppender(CONSOLE_APPENDER_NAME);
+
+ if (consoleAppender == null) {
+ LOG.warn("Console appender '{}' was not found on the root logger; terminal output was not changed.",
+ CONSOLE_APPENDER_NAME);
+ return;
+ }
+
+ // Log the hand-off while the console still shows INFO, so this is the last
+ // informational line the user sees in the terminal.
+ LOG.info("Application fully initialized. Terminal now shows {}+ only; all logs continue to the file.",
+ RUNTIME_CONSOLE_THRESHOLD);
+
+ ThresholdFilter filter = new ThresholdFilter();
+ filter.setLevel(RUNTIME_CONSOLE_THRESHOLD);
+ filter.setContext(context);
+ filter.start();
+ consoleAppender.addFilter(filter);
+ }
+}
diff --git a/src/main/java/com/evolveum/midpoint/integration/catalog/configuration/RequestLoggingFilter.java b/src/main/java/com/evolveum/midpoint/integration/catalog/configuration/RequestLoggingFilter.java
new file mode 100644
index 00000000..d3fff716
--- /dev/null
+++ b/src/main/java/com/evolveum/midpoint/integration/catalog/configuration/RequestLoggingFilter.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010-2025 Evolveum and contributors
+ *
+ * Licensed under the EUPL-1.2 or later.
+ */
+
+package com.evolveum.midpoint.integration.catalog.configuration;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+/**
+ * Logs one line per REST request: HTTP method, URI, resulting status and duration.
+ * Covers every {@code /api/**} endpoint uniformly, so individual controller methods
+ * don't have to repeat request/response boilerplate logging.
+ */
+@Slf4j
+@Component
+public class RequestLoggingFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+ long start = System.currentTimeMillis();
+ String method = request.getMethod();
+ String uri = request.getRequestURI();
+ String query = request.getQueryString();
+ String fullUri = query == null ? uri : uri + "?" + query;
+
+ log.debug("--> {} {}", method, fullUri);
+ try {
+ filterChain.doFilter(request, response);
+ } finally {
+ long duration = System.currentTimeMillis() - start;
+ int status = response.getStatus();
+ if (status >= 500) {
+ log.error("<-- {} {} {} ({} ms)", method, fullUri, status, duration);
+ } else if (status >= 400) {
+ log.warn("<-- {} {} {} ({} ms)", method, fullUri, status, duration);
+ } else {
+ log.info("<-- {} {} {} ({} ms)", method, fullUri, status, duration);
+ }
+ }
+ }
+
+ @Override
+ protected boolean shouldNotFilter(HttpServletRequest request) {
+ // Only log REST API traffic, not SPA static-resource forwarding.
+ return !request.getRequestURI().startsWith("/api/");
+ }
+}
diff --git a/src/main/java/com/evolveum/midpoint/integration/catalog/controller/AuthController.java b/src/main/java/com/evolveum/midpoint/integration/catalog/controller/AuthController.java
index 83ae5d17..e09739e1 100644
--- a/src/main/java/com/evolveum/midpoint/integration/catalog/controller/AuthController.java
+++ b/src/main/java/com/evolveum/midpoint/integration/catalog/controller/AuthController.java
@@ -14,12 +14,14 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
+@Slf4j
@RestController
@RequestMapping("/api/auth")
@Tag(name = "Auth", description = "Authentication endpoints")
@@ -38,20 +40,29 @@ public AuthController(AuthService authService) {
})
@PostMapping("/login")
public ResponseEntity login(@Valid @RequestBody LoginRequestDto request) {
+ log.info("login attempt username={}", request.username());
return authService.login(request.username(), request.password())
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
+ .map(response -> {
+ log.info("login successful username={}", request.username());
+ return ResponseEntity.ok(response);
+ })
+ .orElseGet(() -> {
+ log.warn("login failed username={}", request.username());
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+ });
}
@Operation(summary = "Get organization members", description = "Returns all usernames in the same organization as the given user")
@GetMapping("/organization/members")
public ResponseEntity> getOrganizationMembers(@RequestParam String username) {
+ log.debug("getOrganizationMembers username={}", username);
return ResponseEntity.ok(authService.getOrganizationMembers(username));
}
@Operation(summary = "Get all maintainers", description = "Returns all usernames and organization names — for superuser use")
@GetMapping("/all-maintainers")
public ResponseEntity> getAllMaintainers() {
+ log.debug("getAllMaintainers");
return ResponseEntity.ok(authService.getAllMaintainers());
}
}
diff --git a/src/main/java/com/evolveum/midpoint/integration/catalog/controller/Controller.java b/src/main/java/com/evolveum/midpoint/integration/catalog/controller/Controller.java
index e20ebd2b..8d299e4a 100644
--- a/src/main/java/com/evolveum/midpoint/integration/catalog/controller/Controller.java
+++ b/src/main/java/com/evolveum/midpoint/integration/catalog/controller/Controller.java
@@ -76,11 +76,13 @@ public Controller(ApplicationService applicationService,
})
@GetMapping("/applications/{id}")
public ResponseEntity getApplication(@PathVariable UUID id) {
+ log.debug("getApplication id={}", id);
try {
Application app = applicationService.getApplication(id);
ApplicationDto dto = applicationMapper.mapToApplicationDto(app);
return ResponseEntity.ok(dto);
} catch (RuntimeException ex) {
+ log.error("getApplication failed id={}: {}", id, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to load application: " + ex.getMessage(), ex);
}
@@ -94,9 +96,11 @@ public ResponseEntity getApplication(@PathVariable UUID id) {
})
@GetMapping("/application-tags")
public ResponseEntity> getApplicationTags() {
+ log.debug("getApplicationTags");
try {
return ResponseEntity.ok(applicationService.getApplicationTags());
} catch (RuntimeException ex) {
+ log.warn("getApplicationTags failed: {}", ex.getMessage());
return ResponseEntity.notFound().build();
}
}
@@ -106,6 +110,7 @@ public ResponseEntity> getApplicationTags() {
@ApiResponse(responseCode = "200", description = "Integration method types retrieved successfully")
@GetMapping("/integration-method-types")
public ResponseEntity> getIntegrationMethodTypes() {
+ log.debug("getIntegrationMethodTypes");
return ResponseEntity.ok(applicationService.getIntegrationMethodTypes());
}
@@ -114,6 +119,7 @@ public ResponseEntity> getIntegrationMethodTypes() {
@ApiResponse(responseCode = "200", description = "MidPoint versions retrieved successfully")
@GetMapping("/midpoint-versions")
public ResponseEntity> getMidpointVersions() {
+ log.debug("getMidpointVersions");
return ResponseEntity.ok(applicationService.getMidpointVersions());
}
@@ -125,9 +131,11 @@ public ResponseEntity> getMidpointVersions() {
})
@GetMapping("/countries-of-origin")
public ResponseEntity> getCountriesOfOrigin() {
+ log.debug("getCountriesOfOrigin");
try {
return ResponseEntity.ok(applicationService.getCountriesOfOrigin());
} catch (RuntimeException ex) {
+ log.warn("getCountriesOfOrigin failed: {}", ex.getMessage());
return ResponseEntity.notFound().build();
}
}
@@ -135,6 +143,7 @@ public ResponseEntity> getCountriesOfOrigin() {
@Operation(summary = "Check if connector bundle name exists", description = "Returns true if the specified bundle name is already taken")
@GetMapping("/upload/check-bundle-name")
public ResponseEntity checkBundleNameExists(@RequestParam String bundleName) {
+ log.debug("checkBundleNameExists bundleName={}", bundleName);
boolean exists = applicationService.checkBundleNameExists(bundleName);
return ResponseEntity.ok(exists);
}
@@ -144,11 +153,14 @@ public ResponseEntity checkBundleNameExists(@RequestParam String bundle
public ResponseEntity uploadConnector(
@RequestBody UploadImplementationDto dto,
@RequestHeader(value = "X-User-Name", required = false, defaultValue = "anonymous") String username) {
+ log.info("uploadConnector user={}", username);
try {
return ResponseEntity.status(HttpStatus.OK).body(applicationService.uploadConnector(dto, username));
} catch (IllegalArgumentException e) {
+ log.warn("uploadConnector rejected user={}: {}", username, e.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
} catch (org.springframework.dao.DataIntegrityViolationException e) {
+ log.warn("uploadConnector data conflict user={}: {}", username, e.getMostSpecificCause().getMessage());
throw new ResponseStatusException(HttpStatus.CONFLICT,
"Publish failed due to a data conflict (e.g. duplicate bundle version). " +
"Please ensure the database migration 03_fix_bundle_version_unique_constraint.sql has been applied. " +
@@ -163,6 +175,7 @@ public ResponseEntity uploadConnector(
})
@PostMapping("/upload/continue/{oid}")
public ResponseEntity completeBuildSuccessfully(@RequestBody ContinueForm continueForm, @PathVariable UUID oid) {
+ log.info("completeBuildSuccessfully oid={}", oid);
applicationService.successBuild(oid, continueForm);
return ResponseEntity.ok().build();
}
@@ -174,6 +187,7 @@ public ResponseEntity completeBuildSuccessfully(@RequestBody ContinueForm
})
@PostMapping("/upload/continue/fail/{oid}")
public ResponseEntity completeBuildWithFailure(@RequestBody FailForm failForm, @PathVariable UUID oid) {
+ log.info("completeBuildWithFailure oid={}", oid);
applicationService.failBuild(oid, failForm);
return ResponseEntity.ok().build();
}
@@ -188,9 +202,11 @@ public ResponseEntity> searchApplication(
@RequestBody SearchForm searchForm,
@PathVariable int size,
@PathVariable int page) {
+ log.debug("searchApplication page={} size={}", page, size);
try {
return ResponseEntity.ok(applicationService.searchApplication(searchForm, page, size));
} catch (RuntimeException ex) {
+ log.warn("searchApplication failed page={} size={}: {}", page, size, ex.getMessage());
return ResponseEntity.notFound().build();
}
}
@@ -205,9 +221,11 @@ public ResponseEntity> searchIntegrationMethods(
@RequestBody SearchForm searchForm,
@PathVariable int size,
@PathVariable int page) {
+ log.debug("searchIntegrationMethods page={} size={}", page, size);
try {
return ResponseEntity.ok(applicationService.searchIntegrationMethods(searchForm, page, size));
} catch (RuntimeException ex) {
+ log.warn("searchIntegrationMethods failed page={} size={}: {}", page, size, ex.getMessage());
return ResponseEntity.notFound().build();
}
}
@@ -219,6 +237,7 @@ public ResponseEntity> searchIntegrationMethods(
})
@GetMapping("/requests/{id}")
public ResponseEntity getRequest(@PathVariable Long id) {
+ log.debug("getRequest id={}", id);
return applicationService.getRequest(id)
.map(ResponseEntity::ok)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Request not found"));
@@ -231,6 +250,7 @@ public ResponseEntity getRequest(@PathVariable Long id) {
})
@GetMapping("/applications/{appId}/request")
public ResponseEntity getRequestForApplication(@PathVariable UUID appId) {
+ log.debug("getRequestForApplication appId={}", appId);
return applicationService.getRequestForApplication(appId)
.map(ResponseEntity::ok)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Request not found for application"));
@@ -244,12 +264,16 @@ public ResponseEntity getRequestForApplication(@PathVariable UUID appId
})
@PostMapping("/requests")
public ResponseEntity createRequest(@Valid @RequestBody RequestFormDto dto) {
+ log.info("createRequest");
try {
Request created = applicationService.createRequestFromForm(dto);
+ log.info("createRequest created id={}", created.getId());
return ResponseEntity.status(HttpStatus.CREATED).body(created);
} catch (IllegalArgumentException ex) {
+ log.warn("createRequest rejected: {}", ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (Exception ex) {
+ log.error("createRequest failed: {}", ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to create request: " + ex.getMessage());
}
}
@@ -262,12 +286,15 @@ public ResponseEntity createRequest(@Valid @RequestBody RequestFormDto
})
@DeleteMapping("/requests/{requestId}")
public ResponseEntity cancelRequest(@PathVariable Long requestId) {
+ log.info("cancelRequest requestId={}", requestId);
try {
applicationService.cancelRequest(requestId);
return ResponseEntity.noContent().build();
} catch (IllegalArgumentException ex) {
+ log.warn("cancelRequest not found requestId={}: {}", requestId, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
} catch (Exception ex) {
+ log.error("cancelRequest failed requestId={}: {}", requestId, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to cancel request: " + ex.getMessage());
}
@@ -281,10 +308,12 @@ public ResponseEntity cancelRequest(@PathVariable Long requestId) {
})
@PostMapping("/requests/{requestId}/vote")
public ResponseEntity submitVote(@PathVariable Long requestId, @RequestParam String voter) {
+ log.info("submitVote requestId={} voter={}", requestId, voter);
try {
Vote vote = applicationService.submitVote(requestId, voter);
return ResponseEntity.status(HttpStatus.CREATED).body(vote);
} catch (IllegalArgumentException ex) {
+ log.warn("submitVote rejected requestId={} voter={}: {}", requestId, voter, ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
}
}
@@ -296,6 +325,7 @@ public ResponseEntity submitVote(@PathVariable Long requestId, @RequestPar
})
@GetMapping("/requests/{requestId}/votes/count")
public ResponseEntity getVoteCount(@PathVariable Long requestId) {
+ log.debug("getVoteCount requestId={}", requestId);
long count = applicationService.getVoteCount(requestId);
return ResponseEntity.ok(count);
}
@@ -307,6 +337,7 @@ public ResponseEntity getVoteCount(@PathVariable Long requestId) {
})
@GetMapping("/requests/{requestId}/votes/check")
public ResponseEntity hasUserVoted(@PathVariable Long requestId, @RequestParam String voter) {
+ log.debug("hasUserVoted requestId={} voter={}", requestId, voter);
boolean hasVoted = applicationService.hasUserVoted(requestId, voter);
return ResponseEntity.ok(hasVoted);
}
@@ -318,6 +349,7 @@ public ResponseEntity hasUserVoted(@PathVariable Long requestId, @Reque
})
@GetMapping("/categories/counts")
public ResponseEntity> getCategoryCounts() {
+ log.debug("getCategoryCounts");
return ResponseEntity.ok(applicationService.getCategoryCounts());
}
@@ -329,6 +361,7 @@ public ResponseEntity> getCategoryCounts() {
})
@GetMapping("/applications")
public ResponseEntity> getAllApplications() {
+ log.debug("getAllApplications");
Page page = applicationService.list(Pageable.unpaged(), null, null);
return ResponseEntity.ok(page.getContent());
}
@@ -340,6 +373,7 @@ public ResponseEntity> getAllApplications() {
})
@GetMapping("/connectors/active")
public ResponseEntity> getActiveConnectors() {
+ log.debug("getActiveConnectors");
return ResponseEntity.ok(applicationService.listActiveConnectors());
}
@@ -350,6 +384,7 @@ public ResponseEntity> getActiveConnectors() {
})
@GetMapping("/connectors/catalog")
public ResponseEntity> getCatalogConnectors() {
+ log.debug("getCatalogConnectors");
return ResponseEntity.ok(applicationService.listCatalogConnectors());
}
@@ -360,6 +395,7 @@ public ResponseEntity> getCatalogConnectors() {
})
@GetMapping("/capabilities")
public ResponseEntity> getCapabilities() {
+ log.debug("getCapabilities");
return ResponseEntity.ok(applicationService.getCapabilities());
}
@@ -370,6 +406,7 @@ public ResponseEntity> getCapabilities() {
})
@GetMapping("/statistics/downloads-count")
public ResponseEntity getTotalDownloadsCount() {
+ log.debug("getTotalDownloadsCount");
return ResponseEntity.ok(applicationService.getTotalDownloadsCount());
}
@@ -380,6 +417,7 @@ public ResponseEntity getTotalDownloadsCount() {
})
@GetMapping("/applications/{applicationId}/downloads-count")
public ResponseEntity getApplicationDownloadsCount(@PathVariable UUID applicationId) {
+ log.debug("getApplicationDownloadsCount applicationId={}", applicationId);
return ResponseEntity.ok(applicationService.countDownloadsForApplication(applicationId));
}
@@ -392,9 +430,11 @@ public ResponseEntity getApplicationDownloadsCount(@PathVariable UUID appl
})
@PostMapping("/upload/verify")
public ResponseEntity verify(@RequestBody VerifyBundleInformationForm verifyPayload) {
+ log.info("verify bundle");
try {
return ResponseEntity.status(HttpStatus.OK).body(applicationService.verify(verifyPayload));
} catch (IllegalArgumentException e) {
+ log.warn("verify rejected: {}", e.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
}
}
@@ -407,6 +447,7 @@ public ResponseEntity verify(@RequestBody VerifyBundleInformationForm v
})
@GetMapping("/applications/{applicationId}/implementations")
public ResponseEntity> getIntegrationMethodsByApplicationId(@PathVariable UUID applicationId) {
+ log.debug("getIntegrationMethodsByApplicationId applicationId={}", applicationId);
List items = applicationService.getIntegrationMethodsByApplicationId(applicationId);
return ResponseEntity.ok(items);
}
@@ -418,12 +459,16 @@ public ResponseEntity editIntegrationMethod(
@PathVariable UUID methodId,
@PathVariable String currentRevision,
@RequestBody EditIntegrationMethodDto dto) {
+ log.info("editIntegrationMethod appId={} methodId={} currentRevision={}", appId, methodId, currentRevision);
try {
String newRevision = applicationService.editIntegrationMethod(methodId, currentRevision, dto);
+ log.info("editIntegrationMethod saved methodId={} newRevision={}", methodId, newRevision);
return ResponseEntity.ok(newRevision);
} catch (IllegalStateException e) {
+ log.warn("editIntegrationMethod conflict methodId={}: {}", methodId, e.getMessage());
throw new ResponseStatusException(HttpStatus.CONFLICT, e.getMessage());
} catch (RuntimeException e) {
+ log.warn("editIntegrationMethod not found methodId={}: {}", methodId, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -442,12 +487,15 @@ public ResponseEntity publishIntegrationMethod(
@PathVariable UUID methodId,
@PathVariable String revision,
@RequestHeader(value = "X-User-Name", required = false, defaultValue = "anonymous") String username) {
+ log.info("publishIntegrationMethod appId={} methodId={} revision={} user={}", appId, methodId, revision, username);
try {
applicationService.publishIntegrationMethod(methodId, revision, username);
return ResponseEntity.ok().build();
} catch (IllegalStateException e) {
+ log.warn("publishIntegrationMethod conflict methodId={} revision={}: {}", methodId, revision, e.getMessage());
throw new ResponseStatusException(HttpStatus.CONFLICT, e.getMessage());
} catch (RuntimeException e) {
+ log.warn("publishIntegrationMethod not found methodId={} revision={}: {}", methodId, revision, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -466,12 +514,15 @@ public ResponseEntity rejectIntegrationMethod(
@PathVariable UUID methodId,
@PathVariable String revision,
@RequestHeader(value = "X-User-Name", required = false, defaultValue = "anonymous") String username) {
+ log.info("rejectIntegrationMethod appId={} methodId={} revision={} user={}", appId, methodId, revision, username);
try {
applicationService.rejectIntegrationMethod(methodId, revision, username);
return ResponseEntity.ok().build();
} catch (IllegalStateException e) {
+ log.warn("rejectIntegrationMethod conflict methodId={} revision={}: {}", methodId, revision, e.getMessage());
throw new ResponseStatusException(HttpStatus.CONFLICT, e.getMessage());
} catch (RuntimeException e) {
+ log.warn("rejectIntegrationMethod not found methodId={} revision={}: {}", methodId, revision, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -489,10 +540,12 @@ public ResponseEntity addConnectorToIntegrationMethod(
@PathVariable String revision,
@RequestBody AddConnectorDto dto,
@RequestHeader(value = "X-User-Name", required = false, defaultValue = "anonymous") String username) {
+ log.info("addConnectorToIntegrationMethod appId={} methodId={} revision={} user={}", appId, methodId, revision, username);
try {
applicationService.addConnectorToIntegrationMethod(appId, methodId, revision, dto, username);
return ResponseEntity.ok().build();
} catch (RuntimeException e) {
+ log.warn("addConnectorToIntegrationMethod not found methodId={} revision={}: {}", methodId, revision, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -503,6 +556,7 @@ public ResponseEntity> getConnectorsForIntegrati
@PathVariable UUID appId,
@PathVariable UUID methodId,
@PathVariable String revision) {
+ log.debug("getConnectorsForIntegrationMethod methodId={} revision={}", methodId, revision);
return ResponseEntity.ok(applicationService.getConnectorsForIntegrationMethod(methodId, revision));
}
@@ -519,10 +573,12 @@ public ResponseEntity updateConnector(
@PathVariable String revision,
@PathVariable Integer connectorId,
@RequestBody EditConnectorDto dto) {
+ log.info("updateConnector appId={} methodId={} revision={} connectorId={}", appId, methodId, revision, connectorId);
try {
applicationService.updateConnector(methodId, revision, connectorId, dto);
return ResponseEntity.ok().build();
} catch (RuntimeException e) {
+ log.warn("updateConnector not found methodId={} connectorId={}: {}", methodId, connectorId, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -540,11 +596,13 @@ public ResponseEntity updateConnectorCompatibility(
@PathVariable String revision,
@PathVariable Integer connectorId,
@RequestBody UpdateConnectorCompatibilityDto dto) {
+ log.info("updateConnectorCompatibility appId={} methodId={} revision={} connectorId={}", appId, methodId, revision, connectorId);
try {
applicationService.updateConnectorCompatibility(methodId, revision, connectorId,
dto.connectorVersionFrom(), dto.connectorVersionTo());
return ResponseEntity.ok().build();
} catch (RuntimeException e) {
+ log.warn("updateConnectorCompatibility not found methodId={} connectorId={}: {}", methodId, connectorId, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -561,10 +619,12 @@ public ResponseEntity deleteConnectorFromIntegrationMethod(
@PathVariable UUID methodId,
@PathVariable String revision,
@PathVariable Integer connectorId) {
+ log.info("deleteConnectorFromIntegrationMethod appId={} methodId={} revision={} connectorId={}", appId, methodId, revision, connectorId);
try {
applicationService.deleteConnectorFromIntegrationMethod(methodId, revision, connectorId);
return ResponseEntity.ok().build();
} catch (RuntimeException e) {
+ log.warn("deleteConnectorFromIntegrationMethod not found methodId={} connectorId={}: {}", methodId, connectorId, e.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}
@@ -583,19 +643,24 @@ public ResponseEntity deleteConnectorFromIntegrationMethod(
public ResponseEntity uploadLogo(
@PathVariable UUID id,
@RequestParam("file") MultipartFile file) {
+ log.info("uploadLogo id={} filename={} size={}", id, file.getOriginalFilename(), file.getSize());
try {
Application application = applicationService.getApplication(id);
logoStorageService.saveLogo(application, file);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException ex) {
+ log.warn("uploadLogo rejected id={}: {}", id, ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (RuntimeException ex) {
if (ex.getMessage() != null && ex.getMessage().contains("not found")) {
+ log.warn("uploadLogo not found id={}: {}", id, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
}
+ log.error("uploadLogo failed id={}: {}", id, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to upload logo: " + ex.getMessage(), ex);
} catch (IOException ex) {
+ log.error("uploadLogo file save failed id={}: {}", id, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to save logo file: " + ex.getMessage(), ex);
}
@@ -613,18 +678,23 @@ public ResponseEntity uploadLogo(
public ResponseEntity uploadTutorial(
@PathVariable UUID id,
@RequestParam("file") MultipartFile file) {
+ log.info("uploadTutorial methodId={} filename={} size={}", id, file.getOriginalFilename(), file.getSize());
try {
tutorialStorageService.saveTutorial(id, file);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException ex) {
+ log.warn("uploadTutorial rejected methodId={}: {}", id, ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (RuntimeException ex) {
if (ex.getMessage() != null && ex.getMessage().contains("not found")) {
+ log.warn("uploadTutorial not found methodId={}: {}", id, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
}
+ log.error("uploadTutorial failed methodId={}: {}", id, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to upload tutorial: " + ex.getMessage(), ex);
} catch (IOException ex) {
+ log.error("uploadTutorial file save failed methodId={}: {}", id, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to save tutorial file: " + ex.getMessage(), ex);
}
@@ -637,18 +707,24 @@ public ResponseEntity uploadTutorialForRevision(
@PathVariable UUID methodId,
@PathVariable String revision,
@RequestParam("file") MultipartFile file) {
+ log.info("uploadTutorialForRevision appId={} methodId={} revision={} filename={} size={}",
+ appId, methodId, revision, file.getOriginalFilename(), file.getSize());
try {
tutorialStorageService.saveTutorialForRevision(methodId, revision, file);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException ex) {
+ log.warn("uploadTutorialForRevision rejected methodId={} revision={}: {}", methodId, revision, ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (RuntimeException ex) {
if (ex.getMessage() != null && ex.getMessage().contains("not found")) {
+ log.warn("uploadTutorialForRevision not found methodId={} revision={}: {}", methodId, revision, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
}
+ log.error("uploadTutorialForRevision failed methodId={} revision={}: {}", methodId, revision, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to upload tutorial: " + ex.getMessage(), ex);
} catch (IOException ex) {
+ log.error("uploadTutorialForRevision file save failed methodId={} revision={}: {}", methodId, revision, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to save tutorial file: " + ex.getMessage(), ex);
}
@@ -660,6 +736,7 @@ public ResponseEntity> listTutorialFiles(
@PathVariable UUID appId,
@PathVariable UUID methodId,
@PathVariable String revision) {
+ log.debug("listTutorialFiles methodId={} revision={}", methodId, revision);
return ResponseEntity.ok(tutorialStorageService.listTutorialFiles(methodId, revision));
}
@@ -670,6 +747,7 @@ public ResponseEntity downloadTutorialFile(
@PathVariable UUID methodId,
@PathVariable String revision,
@RequestParam("name") String name) {
+ log.debug("downloadTutorialFile methodId={} revision={} name={}", methodId, revision, name);
try {
Path file = tutorialStorageService.resolveTutorialFile(methodId, revision, name);
byte[] bytes = Files.readAllBytes(file);
@@ -679,10 +757,13 @@ public ResponseEntity downloadTutorialFile(
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + name + "\"")
.body(bytes);
} catch (IllegalArgumentException ex) {
+ log.warn("downloadTutorialFile rejected methodId={} name={}: {}", methodId, name, ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (RuntimeException ex) {
+ log.warn("downloadTutorialFile not found methodId={} name={}: {}", methodId, name, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
} catch (IOException ex) {
+ log.error("downloadTutorialFile read failed methodId={} name={}: {}", methodId, name, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to read tutorial file: " + ex.getMessage(), ex);
}
@@ -701,6 +782,7 @@ public ResponseEntity downloadBundle(
@PathVariable UUID methodId,
@PathVariable String revision,
HttpServletRequest request) {
+ log.info("downloadBundle appId={} methodId={} revision={}", appId, methodId, revision);
try {
BundleService.Bundle bundle = bundleService.buildBundle(methodId, revision);
try {
@@ -717,8 +799,10 @@ public ResponseEntity downloadBundle(
}
return responseBuilder.body(bundle.data());
} catch (IllegalArgumentException ex) {
+ log.warn("downloadBundle not found methodId={} revision={}: {}", methodId, revision, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
} catch (IOException ex) {
+ log.error("downloadBundle build failed methodId={} revision={}: {}", methodId, revision, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to build bundle: " + ex.getMessage(), ex);
}
@@ -731,12 +815,15 @@ public ResponseEntity deleteTutorialFile(
@PathVariable UUID methodId,
@PathVariable String revision,
@RequestParam("name") String name) {
+ log.info("deleteTutorialFile methodId={} revision={} name={}", methodId, revision, name);
try {
tutorialStorageService.deleteTutorialFile(methodId, revision, name);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException ex) {
+ log.warn("deleteTutorialFile rejected methodId={} name={}: {}", methodId, name, ex.getMessage());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (IOException ex) {
+ log.error("deleteTutorialFile failed methodId={} name={}: {}", methodId, name, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to delete tutorial file: " + ex.getMessage(), ex);
}
@@ -753,10 +840,12 @@ public ResponseEntity deleteTutorialFile(
public ResponseEntity getLogo(
@PathVariable UUID id,
@RequestHeader(value = HttpHeaders.IF_NONE_MATCH, required = false) String ifNoneMatch) {
+ log.debug("getLogo id={}", id);
Application application;
try {
application = applicationService.getApplication(id);
} catch (RuntimeException ex) {
+ log.warn("getLogo application not found id={}: {}", id, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Application not found");
}
@@ -802,14 +891,17 @@ private String detectContentType(String logoPath) {
})
@DeleteMapping("/applications/{id}/logo")
public ResponseEntity deleteLogo(@PathVariable UUID id) {
+ log.info("deleteLogo id={}", id);
try {
Application application = applicationService.getApplication(id);
logoStorageService.deleteLogo(application);
return ResponseEntity.noContent().build();
} catch (RuntimeException ex) {
if (ex.getMessage() != null && ex.getMessage().contains("not found")) {
+ log.warn("deleteLogo not found id={}: {}", id, ex.getMessage());
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
}
+ log.error("deleteLogo failed id={}: {}", id, ex.getMessage(), ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to delete logo: " + ex.getMessage(), ex);
}
@@ -824,6 +916,7 @@ public ResponseEntity deleteLogo(@PathVariable UUID id) {
})
@GetMapping("/recently-used")
public ResponseEntity> getRecentlyUsed() {
+ log.debug("getRecentlyUsed");
return ResponseEntity.ok(applicationService.getRecentlyUsedApplications());
}
@@ -836,6 +929,7 @@ public ResponseEntity> getRecentlyUsed() {
public ResponseEntity recordRecentlyUsed(
@PathVariable UUID applicationId,
@RequestHeader(value = "X-User-Name", required = false, defaultValue = "anonymous") String username) {
+ log.info("recordRecentlyUsed applicationId={} user={}", applicationId, username);
applicationService.recordRecentlyUsed(applicationId, username);
return ResponseEntity.noContent().build();
}
diff --git a/src/main/java/com/evolveum/midpoint/integration/catalog/service/ApplicationService.java b/src/main/java/com/evolveum/midpoint/integration/catalog/service/ApplicationService.java
index 80035751..284d44cd 100644
--- a/src/main/java/com/evolveum/midpoint/integration/catalog/service/ApplicationService.java
+++ b/src/main/java/com/evolveum/midpoint/integration/catalog/service/ApplicationService.java
@@ -18,7 +18,9 @@
import com.evolveum.midpoint.integration.catalog.repository.*;
import com.evolveum.midpoint.integration.catalog.repository.adapter.ApplicationReadPort;
+import ch.qos.logback.classic.Logger;
import lombok.extern.slf4j.Slf4j;
+import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@@ -42,6 +44,9 @@
@Service
public class ApplicationService {
+ private static final Logger LOG
+ = (Logger) LoggerFactory.getLogger(ApplicationService.class);
+
private final ApplicationRepository applicationRepository;
private final ApplicationTagRepository applicationTagRepository;
private final CountryOfOriginRepository countryOfOriginRepository;
@@ -169,43 +174,52 @@ public List getCapabilities() {
@Transactional
public String uploadConnector(UploadImplementationDto dto, String username) {
+ LOG.info("uploadConnector user={}", username);
return connectorUploadService.uploadConnector(dto, username);
}
@Transactional
public String editIntegrationMethod(UUID methodId, String currentRevision, EditIntegrationMethodDto dto) {
+ LOG.info("editIntegrationMethod methodId={} currentRevision={}", methodId, currentRevision);
return connectorUploadService.editIntegrationMethod(methodId, currentRevision, dto);
}
@Transactional
public void publishIntegrationMethod(UUID methodId, String revision, String username) {
+ LOG.info("publishIntegrationMethod methodId={} revision={} user={}", methodId, revision, username);
connectorUploadService.publishIntegrationMethod(methodId, revision, username);
}
@Transactional
public void rejectIntegrationMethod(UUID methodId, String revision, String username) {
+ LOG.info("rejectIntegrationMethod methodId={} revision={} user={}", methodId, revision, username);
connectorUploadService.rejectIntegrationMethod(methodId, revision, username);
}
@Transactional
public void addConnectorToIntegrationMethod(UUID appId, UUID methodId, String revision,
AddConnectorDto dto, String username) {
+ LOG.info("addConnectorToIntegrationMethod appId={} methodId={} revision={} user={}", appId, methodId, revision, username);
connectorUploadService.addConnectorToIntegrationMethod(appId, methodId, revision, dto, username);
}
@Transactional
public void updateConnector(UUID methodId, String revision, Integer connectorId, EditConnectorDto dto) {
+ LOG.info("updateConnector methodId={} revision={} connectorId={}", methodId, revision, connectorId);
connectorUploadService.updateConnector(methodId, revision, connectorId, dto);
}
@Transactional
public void deleteConnectorFromIntegrationMethod(UUID methodId, String revision, Integer connectorId) {
+ LOG.info("deleteConnectorFromIntegrationMethod methodId={} revision={} connectorId={}", methodId, revision, connectorId);
connectorUploadService.deleteConnectorFromIntegrationMethod(methodId, revision, connectorId);
}
@Transactional
public void updateConnectorCompatibility(UUID methodId, String revision, Integer connectorId,
String connectorVersionFrom, String connectorVersionTo) {
+ LOG.info("updateConnectorCompatibility methodId={} revision={} connectorId={} from={} to={}",
+ methodId, revision, connectorId, connectorVersionFrom, connectorVersionTo);
connectorUploadService.updateConnectorCompatibility(methodId, revision, connectorId,
connectorVersionFrom, connectorVersionTo);
}
@@ -219,11 +233,13 @@ public List getConnectorsForIntegrationMethod(UUID me
@Transactional
public void successBuild(UUID oid, ContinueForm continueForm) {
+ LOG.info("successBuild oid={}", oid);
buildCallbackService.successBuild(oid, continueForm);
}
@Transactional
public void failBuild(UUID oid, FailForm failForm) {
+ LOG.info("failBuild oid={}", oid);
buildCallbackService.failBuild(oid, failForm);
}
@@ -281,6 +297,7 @@ public List getRequests() {
@Transactional
public Request createRequestFromForm(RequestFormDto dto) {
+ LOG.info("createRequestFromForm");
return requestVotingService.createRequestFromForm(dto);
}
@@ -293,6 +310,7 @@ public Optional getRequestForApplication(UUID appId) {
}
public Vote submitVote(Long requestId, String voter) {
+ LOG.info("submitVote requestId={} voter={}", requestId, voter);
return requestVotingService.submitVote(requestId, voter);
}
@@ -305,10 +323,12 @@ public boolean hasUserVoted(Long requestId, String voter) {
}
public void cancelRequest(Long requestId) {
+ LOG.info("cancelRequest requestId={}", requestId);
requestVotingService.cancelRequest(requestId);
}
public void recordMethodDownload(UUID methodId, String revision, String ip, String userAgent) {
+ LOG.info("recordMethodDownload methodId={} revision={} ip={}", methodId, revision, ip);
connectorDownloadService.recordMethodDownload(methodId, revision, ip, userAgent);
}
@@ -410,6 +430,7 @@ public List getRecentlyUsedApplications() {
@Transactional
public void recordRecentlyUsed(UUID applicationId, String userId) {
+ LOG.info("recordRecentlyUsed applicationId={} user={}", applicationId, userId);
recentlyUsedApplicationRepository.deleteByUserIdAndApplicationId(userId, applicationId);
recentlyUsedApplicationRepository.flush();
RecentlyUsedApplication entry = new RecentlyUsedApplication()
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 07c4d4b0..36aa0d18 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -18,12 +18,13 @@ spring.jpa.show-sql=false
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
-# Set logging level
-logging.level.root=INFO
-logging.level.com.example.service=INFO
-logging.level.org.hibernate.SQL=INFO
-logging.level.org.hibernate.orm.jdbc.bind=INFO
-logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %logger{36} - %msg%n
+# Logging configuration file (Logback). Levels/appenders/patterns live in log4j.xml.
+logging.config=classpath:log4j.xml
+
+# Render the startup banner (banner.txt) through the logging system instead of
+# straight to stdout, so it is written at the top of the log file. It still shows
+# in the terminal too, because the console appender is attached during startup.
+spring.main.banner-mode=log
# GitHub client
github.apiToken=
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
index ce8c8ad3..66b5b678 100644
--- a/src/main/resources/banner.txt
+++ b/src/main/resources/banner.txt
@@ -9,7 +9,7 @@
|___/ |___/ by Evolveum and partners
Licensed under the EUPL-1.2 or later.
- Version: ${project.version}
- Sources: https://github.com/Evolveum/integration-catalog, branch: ${git.branch}, build: ${git.describe}
- Bug reporting system: ${project.issueManagement.url}
+ Version: @project.version@
+ Sources: https://github.com/Evolveum/integration-catalog, branch: @git.branch@, build: @git.commit.id.describe@
+ Bug reporting system: @project.issueManagement.url@
Product information: https://midpoint.evolveum.com
diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml
index 80098301..b8520b62 100644
--- a/src/main/resources/log4j.xml
+++ b/src/main/resources/log4j.xml
@@ -1,35 +1,37 @@
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}.%M %L - %msg%n
-
-
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}.%M %L - %msg%n
+
+
- integration-catalog.log
+ ./integration-catalog/logs/integration-catalog.log
- app.%d{yyyy-MM-dd-mm}.%i.log.zip
- 20
-
-
+ ./integration-catalog/logs/app.%d{yyyy-MM-dd-HH}.%i.log.zip
10MB
-
+ 24
+
%d{HH:mm:ss.SSS} [%thread] %-5level %class{36}.%M %L - %msg%n
-
-
+
-
+
-
-
-
+
+
-
\ No newline at end of file
+