diff options
4 files changed, 258 insertions, 1 deletions
diff --git a/basicConfig/ms-proxyservice/logback_config.xml b/basicConfig/ms-proxyservice/logback_config.xml index d2bf5d85..a7e1552b 100644 --- a/basicConfig/ms-proxyservice/logback_config.xml +++ b/basicConfig/ms-proxyservice/logback_config.xml @@ -52,6 +52,21 @@ </triggeringPolicy> </appender> + <appender name="statisticJson" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender--> + <File>${catalina.base}/logs/eidas-ms-statistic_proxyservice.log</File> + <encoder> + <pattern>%m%n</pattern> + </encoder> + <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <maxIndex>9999</maxIndex> + <FileNamePattern>${catalina.base}/logs/eidas-ms-statistic_proxyservice.%i</FileNamePattern> + </rollingPolicy> + <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <MaxFileSize>10000KB</MaxFileSize> + </triggeringPolicy> + </appender> + <appender name="stdout" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--See also http://logback.qos.ch/manual/appenders.html#RollingFileAppender--> <File>${catalina.base}/logs/console.log</File> @@ -72,6 +87,9 @@ <logger name="at.asitplus.eidas.specific.core.logger.StatisticLogger" additivity="false" level="info"> <appender-ref ref="statistic"/> </logger> + <logger name="at.asitplus.eidas.specific.proxy.logger.AdvancedStatisicLogger" additivity="false" level="info"> + <appender-ref ref="statisticJson"/> + </logger> <logger name="at.asitplus.eidas.specific.core.logger.RevisionLogger" level="info"> <appender-ref ref="reversion"/> </logger> diff --git a/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/logger/AdvancedStatisicLogger.java b/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/logger/AdvancedStatisicLogger.java new file mode 100644 index 00000000..fda988a6 --- /dev/null +++ b/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/logger/AdvancedStatisicLogger.java @@ -0,0 +1,171 @@ +package at.asitplus.eidas.specific.proxy.logger; + +import java.time.LocalDateTime; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; + +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IEidAuthData; +import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * Extended statistic logger that use a JSON based data model. + * + * @author tlenz + * + */ +@Slf4j +public class AdvancedStatisicLogger implements IStatisticLogger { + + private static final String DATEFORMATER = "yyyy.MM.dd-HH:mm:ss"; + private static final String DEFAULT_NO_IDP_ID = "no idpId available"; + + private static final ObjectMapper mapper = new ObjectMapper(); + + private final IStatusMessenger messageService; + + /** + * Build a JSON based statistic logger that uses error messages from a specific source. + * + * @param source i18n message source + */ + public AdvancedStatisicLogger(IStatusMessenger source) { + this.messageService = source; + + } + + @Override + public void logSuccessOperation(IRequest protocolRequest, IAuthData authData, boolean isSsoSession) { + final StatisticLogEntry entry = buildCoreEntry(protocolRequest); + entry.setSuccess(SuccessEntry.builder() + .spSector(protocolRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()) + .withMandates(selectMandateProcessType(authData)) + .build()); + writeEntryToLog(entry); + + } + + @Override + public void logErrorOperation(Throwable throwable) { + log.trace("Advanced statistic logger only logs on SP level"); + + } + + @Override + public void logErrorOperation(Throwable throwable, IRequest errorRequest) { + final StatisticLogEntry entry = buildCoreEntry(errorRequest); + entry.setError(new ErrorEntry(messageService.getResponseErrorCode(throwable), throwable.getMessage())); + writeEntryToLog(entry); + + } + + @Override + public void internalTesting() throws Exception { + log.trace("Not implemented for a File-based logger"); + + } + + private StatisticLogEntry buildCoreEntry(IRequest pendingRequest) { + return new StatisticLogEntry( + LocalDateTime.now(), + pendingRequest.getUniqueTransactionIdentifier(), + pendingRequest.getServiceProviderConfiguration() != null + && pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier() != null + ? pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier() : DEFAULT_NO_IDP_ID); + + } + + private MandateProcess selectMandateProcessType(IAuthData authData) { + if (authData instanceof IEidAuthData && ((IEidAuthData)authData).isUseMandate()) { + return authData.getGenericData(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, String.class) != null + ? MandateProcess.FOR_LEGAL_PERSON : MandateProcess.FOR_NATURAL_PERSON; + + } else { + return MandateProcess.NONE; + + } + } + + private void writeEntryToLog(StatisticLogEntry entry) { + try { + log.info(mapper.writeValueAsString(entry)); + + } catch (final JsonProcessingException e) { + log.error("Can NOT generate statistic entry for logging", e); + + } + } + + public enum MandateProcess { NONE, FOR_NATURAL_PERSON, FOR_LEGAL_PERSON } + + @Getter + @Setter + @RequiredArgsConstructor + @JsonInclude(Include.NON_NULL) + private static class StatisticLogEntry { + + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonFormat(pattern = DATEFORMATER) + @JsonProperty("timestamp") + private final LocalDateTime timestamp; + + @JsonProperty("txId") + private final String transactionId; + + @JsonProperty("entityId") + private final String idpEntityId; + + @JsonProperty("success") + private SuccessEntry success; + + @JsonProperty("error") + private ErrorEntry error; + + } + + @Getter + @Setter + @Builder + @JsonInclude(Include.NON_NULL) + private static class SuccessEntry { + + @JsonProperty("spSector") + private final String spSector; + + @JsonProperty("withMandates") + private final MandateProcess withMandates; + + } + + @Getter + @Setter + @RequiredArgsConstructor + private static class ErrorEntry { + + @JsonProperty("code") + private final String errorCode; + + @JsonProperty("msg") + private final String errorMessage; + + } + +} diff --git a/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/logger/MultipleStatisticLogger.java b/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/logger/MultipleStatisticLogger.java new file mode 100644 index 00000000..bd771fb2 --- /dev/null +++ b/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/logger/MultipleStatisticLogger.java @@ -0,0 +1,68 @@ +package at.asitplus.eidas.specific.proxy.logger; + +import java.util.Collections; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.collect.Sets; + +import at.asitplus.eidas.specific.core.logger.StatisticLogger; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger; + +/** + * {@link IStatisticLogger} implementation that can log into more than one internal {@link IStatisticLogger}. + * + * @author tlenz + * + */ +public class MultipleStatisticLogger implements IStatisticLogger { + + private final Set<IStatisticLogger> internalLoggers; + + /** + * Build a statistic logger that logs into {@link StatisticLogger} and {@link AdvancedStatisicLogger}. + * + * @param messageService i18n message-source implementation. + */ + public MultipleStatisticLogger(@Autowired IStatusMessenger messageService) { + internalLoggers = Collections.unmodifiableSet( + Sets.newHashSet( + new StatisticLogger(), + new AdvancedStatisicLogger(messageService))); + + } + + + + @Override + public void logSuccessOperation(IRequest protocolRequest, IAuthData authData, boolean isSsoSession) { + internalLoggers.parallelStream() + .forEach(el -> el.logSuccessOperation(protocolRequest, authData, isSsoSession)); + + } + + @Override + public void logErrorOperation(Throwable throwable) { + internalLoggers.parallelStream().forEach(el -> el.logErrorOperation(throwable)); + + } + + @Override + public void logErrorOperation(Throwable throwable, IRequest errorRequest) { + internalLoggers.parallelStream().forEach(el -> el.logErrorOperation(throwable, errorRequest)); + + } + + @Override + public void internalTesting() throws Exception { + for (IStatisticLogger el : internalLoggers) { + el.internalTesting(); + + } + } + +} diff --git a/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml b/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml index 646b851c..3893600e 100644 --- a/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml +++ b/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml @@ -14,7 +14,7 @@ <import resource="specific_eIDAS_core.beans.xml"/> <bean id="eidasStatisticLogger" - class="at.asitplus.eidas.specific.core.logger.StatisticLogger" /> + class="at.asitplus.eidas.specific.proxy.logger.MultipleStatisticLogger" /> <bean id="ProxyAuthenticationDataBuilder" class="at.asitplus.eidas.specific.proxy.builder.ProxyAuthenticationDataBuilder" /> |