package org.simantics.audit.client; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.simantics.audit.AuditLogging; import org.simantics.audit.AuditLogging.Level; import org.simantics.audit.AuditLoggingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AuditLoggingClient { private static final String AUDIT_SERVER_ADDRESS = "org.simantics.audit.serverAddress"; private static final String AUDIT_CLIENT_ID = "org.simantics.audit.clientId"; private static final Logger LOGGER = LoggerFactory.getLogger(AuditLoggingClient.class); private static AuditLoggingClient INSTANCE; private AuditLoggingAPIClient apiClient; private AuditLoggingClient(String clientId, String serverAddress) throws AuditLoggingException { apiClient = new AuditLoggingAPIClient(clientId, serverAddress); } private static AuditLoggingClient fromEnv() throws AuditLoggingException { return fromProps(System.getProperties()); } public static AuditLoggingClient fromProps(Map properties) throws AuditLoggingException { if (INSTANCE == null) { synchronized (AuditLoggingClient.class) { if (INSTANCE == null) { String serverAddress = (String) properties.get(AUDIT_SERVER_ADDRESS); String clientId = (String) properties.get(AUDIT_CLIENT_ID); if (clientId == null || clientId.isEmpty()) clientId = UUID.randomUUID().toString(); if (serverAddress != null && !serverAddress.isEmpty()) { INSTANCE = new AuditLoggingClient(clientId, serverAddress); } else { LOGGER.warn("No {} system property defined so client not configured", AUDIT_SERVER_ADDRESS); } } } } return INSTANCE; } public static String getUUID() throws AuditLoggingException { return fromEnv().apiClient.getUuid(); } public static void sendLog(List keyValues) throws AuditLoggingException { commit(Level.INFO, toMap(keyValues.toArray())); } private static Map toMap(Object... keyValues) { if ((keyValues.length % 2) != 0) throw new IllegalArgumentException("Invalid amount of arguments! " + Arrays.toString(keyValues)); Map results = new HashMap<>(keyValues.length / 2); for (int i = 0; i < keyValues.length; i += 2) { Object key = keyValues[i]; Object value = keyValues[i + 1]; if (!(key instanceof String)) throw new IllegalArgumentException("Key with index " + i + " is not String"); results.put((String) key, value); } return results; } public static void sendLog(Map event) throws AuditLoggingException { commit(Level.INFO, event); } public static void sendError(Map event) throws AuditLoggingException { commit(Level.ERROR, event); } public static void sendError(List keyValues) throws AuditLoggingException { commit(Level.ERROR, toMap(keyValues.toArray())); } public static void sendTrace(Map event) throws AuditLoggingException { commit(Level.TRACE, event); } public static void sendTrace(List keyValues) throws AuditLoggingException { commit(Level.TRACE, toMap(keyValues.toArray())); } private static void commit(Level level, Map message) throws AuditLoggingException { try { AuditLoggingClient client = fromEnv(); if (client == null || client.apiClient == null) { // No can do - at least log to file LOGGER.warn("Audit logging server not configured - printing event to log"); LOGGER.info(message.toString()); } else { AuditLoggingAPIClient apiClient = client.apiClient; switch (level) { case INFO: apiClient.log(message); break; case ERROR: apiClient.error(message); break; case TRACE: apiClient.trace(message); break; default: break; } } } catch (AuditLoggingException e) { // Just for debugging purposes LOGGER.error("Could not send audit event {} with level {}", message, level, e); // log this locally to a file just in case AuditLogging.log("local", message); throw e; } } }