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}