001package com.identityworksllc.iiq.common;
002
003import sailpoint.api.SailPointContext;
004import sailpoint.api.SailPointFactory;
005import sailpoint.api.logging.SyslogThreadLocal;
006import sailpoint.object.SyslogEvent;
007import sailpoint.persistence.Sequencer;
008import sailpoint.tools.GeneralException;
009import sailpoint.tools.Util;
010
011import java.io.PrintWriter;
012import java.io.StringWriter;
013import java.util.concurrent.atomic.AtomicReference;
014
015/**
016 * A utility for generating and committing Syslog events, even where IIQ would not
017 * produce them. The events are saved via an autonomous transaction.
018 */
019public class Syslogger {
020    /**
021     * @see #logEvent(Class, String, Throwable)
022     */
023    public static String logEvent(Class<?> owningClass, String message) throws GeneralException {
024        return logEvent(owningClass, message, null);
025    }
026
027    /**
028     * @see #logEvent(Class, String, Throwable)
029     */
030    public static String logEvent(String message) throws GeneralException {
031        return logEvent(null, message, null);
032    }
033
034    /**
035     * @see #logEvent(Class, String, Throwable)
036     */
037    public static String logEvent(String message, Throwable error) throws GeneralException {
038        return logEvent(null, message, error);
039    }
040
041    /**
042     * Logs a SyslogEvent of ERROR type with a sequential QuickKey, returning that key
043     *
044     * @param owningClass The class invoking this method, which will be logged as the class name, optionally
045     * @param message The message to log (not null)
046     * @param error The error, optionally
047     * @return The quick key generated for this event
048     * @throws GeneralException if any failures occur during logging or creating the private context
049     */
050    public static String logEvent(final Class<?> owningClass, final String message, final Throwable error) throws GeneralException {
051        final String authenticatedUser;
052        final SailPointContext currentContext = SailPointFactory.getCurrentContext();
053        if (currentContext != null && currentContext.getUserName() != null) {
054            authenticatedUser = currentContext.getUserName();
055        } else {
056            authenticatedUser = "???";
057        }
058        final AtomicReference<String> quickKeyRef = new AtomicReference<>();
059        Utilities.withPrivateContext((context) -> {
060            Sequencer sequencer = new Sequencer();
061            String quickKey = sequencer.generateId(context, new SyslogEvent());
062            quickKeyRef.set(quickKey);
063            SyslogThreadLocal.set(Util.stripLeadingChar(quickKey, '0'));
064            SyslogEvent event = new SyslogEvent();
065            event.setQuickKey(quickKey);
066            event.setUsername(authenticatedUser);
067            event.setServer(Util.getHostName());
068            event.setEventLevel("ERROR");
069            event.setThread(Thread.currentThread().getName());
070            event.setMessage(message);
071            if (owningClass != null) {
072                event.setClassname(owningClass.getName());
073            }
074            if (error != null) {
075                try (StringWriter writer = new StringWriter()) {
076                    try (PrintWriter printWriter = new PrintWriter(writer)) {
077                        error.printStackTrace(printWriter);
078                    }
079                    writer.flush();
080                    event.setStacktrace(writer.toString());
081                }
082            }
083
084            context.saveObject(event);
085            context.commitTransaction();
086        });
087        return quickKeyRef.get();
088    }
089
090    /**
091     * Private utility constructor
092     */
093    private Syslogger() {
094
095    }
096}