001package com.identityworksllc.iiq.common; 002 003import lombok.Builder; 004import lombok.Getter; 005import lombok.Setter; 006import sailpoint.api.SailPointContext; 007import sailpoint.api.SailPointFactory; 008import sailpoint.api.logging.SyslogThreadLocal; 009import sailpoint.object.SyslogEvent; 010import sailpoint.persistence.Sequencer; 011import sailpoint.tools.GeneralException; 012import sailpoint.tools.Util; 013 014import javax.validation.constraints.NotNull; 015import java.io.PrintWriter; 016import java.io.StringWriter; 017import java.util.concurrent.atomic.AtomicReference; 018 019/** 020 * A utility for generating and committing Syslog events, even where IIQ would not 021 * produce them. The events are saved via an autonomous transaction. 022 */ 023public class Syslogger { 024 /** 025 * Argument VO for syslog events 026 */ 027 @Setter 028 @Getter 029 @Builder 030 public static final class SyslogArgs { 031 /** 032 * The error, optionally 033 */ 034 private Throwable error; 035 036 /** 037 * The event level (ERROR, INFO, WARN) 038 */ 039 private String eventLevel; 040 041 /** 042 * The logged in user, optionally 043 */ 044 private String loggedInUser; 045 046 /** 047 * The message to log (not null) 048 */ 049 @NotNull 050 private String message; 051 052 /** 053 * The owning class, optionally 054 */ 055 private Class<?> owningClass; 056 } 057 058 /** 059 * Event level error 060 */ 061 public static final String EVENT_LEVEL_ERROR = "ERROR"; 062 063 /** 064 * Event level info 065 */ 066 public static final String EVENT_LEVEL_INFO = "INFO"; 067 068 /** 069 * Event level warn 070 */ 071 public static final String EVENT_LEVEL_WARN = "WARN"; 072 073 /** 074 * Private utility constructor 075 */ 076 private Syslogger() { 077 078 } 079 080 /** 081 * @see #logEvent(Class, String, Throwable) 082 */ 083 public static String logEvent(Class<?> owningClass, String message) throws GeneralException { 084 return logEvent(owningClass, message, null); 085 } 086 087 /** 088 * @see #logEvent(Class, String, Throwable) 089 */ 090 public static String logEvent(String message) throws GeneralException { 091 return logEvent(null, message, null); 092 } 093 094 /** 095 * @see #logEvent(Class, String, Throwable) 096 */ 097 public static String logEvent(String message, Throwable error) throws GeneralException { 098 return logEvent(null, message, error); 099 } 100 101 public static String logEvent(final Class<?> owningClass, final String message, final Throwable error) throws GeneralException { 102 return logEvent(owningClass, message, error, EVENT_LEVEL_ERROR); 103 } 104 105 /** 106 * Logs a SyslogEvent of ERROR type with a sequential QuickKey, returning that key 107 * 108 * @param owningClass The class invoking this method, which will be logged as the class name, optionally 109 * @param message The message to log (not null) 110 * @param error The error, optionally 111 * @return The quick key generated for this event 112 * @throws GeneralException if any failures occur during logging or creating the private context 113 */ 114 public static String logEvent(final Class<?> owningClass, final String message, final Throwable error, final String eventLevel) throws GeneralException { 115 final String authenticatedUser; 116 final SailPointContext currentContext = SailPointFactory.getCurrentContext(); 117 if (currentContext != null && currentContext.getUserName() != null) { 118 authenticatedUser = currentContext.getUserName(); 119 } else { 120 authenticatedUser = "???"; 121 } 122 final AtomicReference<String> quickKeyRef = new AtomicReference<>(); 123 Utilities.withPrivateContext((context) -> { 124 Sequencer sequencer = new Sequencer(); 125 String quickKey = sequencer.generateId(context, new SyslogEvent()); 126 quickKeyRef.set(quickKey); 127 SyslogThreadLocal.set(Util.stripLeadingChar(quickKey, '0')); 128 SyslogEvent event = new SyslogEvent(); 129 event.setQuickKey(quickKey); 130 event.setUsername(authenticatedUser); 131 event.setServer(Util.getHostName()); 132 event.setEventLevel(eventLevel); 133 event.setThread(Thread.currentThread().getName()); 134 event.setMessage(message); 135 if (owningClass != null) { 136 event.setClassname(owningClass.getName()); 137 } 138 if (error != null) { 139 try (StringWriter writer = new StringWriter()) { 140 try (PrintWriter printWriter = new PrintWriter(writer)) { 141 error.printStackTrace(printWriter); 142 } 143 writer.flush(); 144 event.setStacktrace(writer.toString()); 145 } 146 } 147 148 context.saveObject(event); 149 context.commitTransaction(); 150 }); 151 return quickKeyRef.get(); 152 } 153}