diff --git a/pom.xml b/pom.xml
index f044eec..8a29c31 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.jenkins-ci.plugins
plugin
- 3.43
+ 3.50
@@ -14,7 +14,7 @@
Audit Trail
2.7-SNAPSHOT
- 2.60.3
+ 2.138.1
8
@@ -39,6 +39,17 @@
3.0.2
true
+
+ io.jenkins
+ configuration-as-code
+ test
+
+
+ io.jenkins
+ configuration-as-code
+ tests
+ test
+
@@ -55,7 +66,6 @@
org.jenkins-ci.tools
maven-hpi-plugin
- 2.5
FINE
@@ -78,4 +88,17 @@
https://repo.jenkins-ci.org/public/
+
+
+
+
+ io.jenkins.tools.bom
+ bom-2.138.x
+ 3
+ import
+ pom
+
+
+
+
diff --git a/src/main/java/hudson/plugins/audit_trail/AuditLogger.java b/src/main/java/hudson/plugins/audit_trail/AuditLogger.java
index 8d3c407..00e9679 100644
--- a/src/main/java/hudson/plugins/audit_trail/AuditLogger.java
+++ b/src/main/java/hudson/plugins/audit_trail/AuditLogger.java
@@ -1,14 +1,15 @@
package hudson.plugins.audit_trail;
+import hudson.DescriptorExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
-import java.io.IOException;
/**
* @author Nicolas De Loof
+ * @author Pierre Beitz
*/
public abstract class AuditLogger implements Describable, ExtensionPoint {
@@ -16,7 +17,7 @@ public abstract class AuditLogger implements Describable, Extension
public abstract void log(String event);
- public Descriptor getDescriptor() {
+ public Descriptor getDescriptor() {
return Jenkins.getInstance().getDescriptorOrDie(getClass());
}
@@ -31,4 +32,10 @@ public void cleanUp() throws SecurityException {
// default does nothing
}
+ /**
+ * Returns all the registered {@link AuditLogger} descriptors.
+ */
+ public static DescriptorExtensionList> all() {
+ return Jenkins.getInstance().getDescriptorList(AuditLogger.class);
+ }
}
diff --git a/src/main/java/hudson/plugins/audit_trail/AuditTrailFilter.java b/src/main/java/hudson/plugins/audit_trail/AuditTrailFilter.java
index 713e95a..5fcccfc 100644
--- a/src/main/java/hudson/plugins/audit_trail/AuditTrailFilter.java
+++ b/src/main/java/hudson/plugins/audit_trail/AuditTrailFilter.java
@@ -23,9 +23,14 @@
*/
package hudson.plugins.audit_trail;
+import com.google.inject.Injector;
+import hudson.Extension;
+import hudson.init.Initializer;
import hudson.model.User;
+import hudson.util.PluginServletFilter;
import jenkins.model.Jenkins;
+import javax.inject.Inject;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@@ -34,21 +39,33 @@
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import static hudson.init.InitMilestone.PLUGINS_PREPARED;
/**
* Servlet filter to watch requests and log those we are interested in.
* @author Alan Harder
+ * @author Pierre Beitz
*/
+@Extension
public class AuditTrailFilter implements Filter {
private static final Logger LOGGER = Logger.getLogger(AuditTrailFilter.class.getName());
private static Pattern uriPattern = null;
- private final AuditTrailPlugin plugin;
+ @Inject
+ private AuditTrailPlugin configuration;
+ /**
+ * @deprecated as of 2.6
+ **/
+ @Deprecated
public AuditTrailFilter(AuditTrailPlugin plugin) {
- this.plugin = plugin;
+ this.configuration = plugin;
+ }
+
+ public AuditTrailFilter() {
+ // used by the injector
}
public void init(FilterConfig fc) {
@@ -85,7 +102,7 @@ public void doFilter(ServletRequest request, ServletResponse res, FilterChain ch
if(LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "Audit request {0} by user {1}", new Object[]{uri, username});
- plugin.onRequest(uri, extra, username);
+ onRequest(uri, extra, username);
} else {
LOGGER.log(Level.FINEST, "Skip audit for request {0}", uri);
}
@@ -94,4 +111,27 @@ public void doFilter(ServletRequest request, ServletResponse res, FilterChain ch
public void destroy() {
}
+
+ // the default milestone doesn't seem right, as the injector is not available yet (at least with the JenkinsRule)
+ @Initializer(after = PLUGINS_PREPARED)
+ public static void init() throws ServletException {
+ Injector injector = Jenkins.getInstance().getInjector();
+ if (injector == null) {
+ return;
+ }
+ PluginServletFilter.addFilter(injector.getInstance(AuditTrailFilter.class));
+ }
+
+ private void onRequest(String uri, String extra, String username) {
+ if (configuration != null) {
+ if (configuration.isStarted()) {
+ for (AuditLogger logger : configuration.getLoggers()) {
+ logger.log(uri + extra + " by " + username);
+ }
+ } else {
+ LOGGER.warning("Plugin configuration not properly injected, please report an issue to the Audit Trail Plugin");
+ }
+ }
+
+ }
}
diff --git a/src/main/java/hudson/plugins/audit_trail/AuditTrailPlugin.java b/src/main/java/hudson/plugins/audit_trail/AuditTrailPlugin.java
index 30be9d4..f0421f3 100644
--- a/src/main/java/hudson/plugins/audit_trail/AuditTrailPlugin.java
+++ b/src/main/java/hudson/plugins/audit_trail/AuditTrailPlugin.java
@@ -24,75 +24,104 @@
package hudson.plugins.audit_trail;
import hudson.DescriptorExtensionList;
-import hudson.Plugin;
-import hudson.model.*;
-import hudson.model.Descriptor.FormException;
+import hudson.Extension;
+
+import hudson.model.AbstractBuild;
+import hudson.model.Descriptor;
+import hudson.model.Run;
import hudson.util.FormValidation;
-import hudson.util.PluginServletFilter;
-import jenkins.model.Jenkins;
+import jenkins.model.GlobalConfiguration;
import net.sf.json.JSONObject;
+import org.jenkinsci.Symbol;
+import org.kohsuke.accmod.Restricted;
+import org.kohsuke.accmod.restrictions.DoNotUse;
+import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
+import javax.annotation.PostConstruct;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Optional;
+import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* Keep audit trail of particular Jenkins operations, such as configuring jobs.
+ *
* @author Alan Harder
+ * @author Pierre Beitz
*/
-public class AuditTrailPlugin extends Plugin {
+@Symbol("audit-trail")
+@Extension
+public class AuditTrailPlugin extends GlobalConfiguration {
+
+ private static final Logger LOGGER = Logger.getLogger(AuditTrailPlugin.class.getName());
private String pattern = ".*/(?:configSubmit|doDelete|postBuildResult|enable|disable|"
- + "cancelQueue|stop|toggleLogKeep|doWipeOutWorkspace|createItem|createView|toggleOffline|"
- + "cancelQuietDown|quietDown|restart|exit|safeExit)";
+ + "cancelQueue|stop|toggleLogKeep|doWipeOutWorkspace|createItem|createView|toggleOffline|"
+ + "cancelQuietDown|quietDown|restart|exit|safeExit)";
private boolean logBuildCause = true;
- private List loggers = new ArrayList();
+ private List loggers = new ArrayList<>();
private transient boolean started;
private transient String log;
- private transient int limit = 1, count = 1;
public String getPattern() { return pattern; }
public boolean getLogBuildCause() { return logBuildCause; }
public List getLoggers() { return loggers; }
- @Override public void start() throws Exception {
- // Set a default value; will be overridden by load() once customized:
+ public AuditTrailPlugin() {
load();
- applySettings();
-
- // Add Filter to watch all requests and log matching ones
- PluginServletFilter.addFilter(new AuditTrailFilter(this));
}
- @Override public void configure(StaplerRequest req, JSONObject formData)
- throws IOException, ServletException, FormException {
- pattern = formData.optString("pattern");
- logBuildCause = formData.optBoolean("logBuildCause", true);
+ @Override
+ public boolean configure(StaplerRequest req, JSONObject formData) {
// readResolve makes sure loggers is initialized, so it should never be null.
+ // TODO this should probably be moved somewhere else
loggers.forEach(AuditLogger::cleanUp);
- loggers = Descriptor.newInstancesFromHeteroList(
- req, formData, "loggers", getLoggerDescriptors());
- save();
+ req.bindJSON(this, formData);
applySettings();
+ return true;
}
+ @DataBoundSetter
+ public void setPattern(String pattern) {
+ this.pattern = Optional.ofNullable(pattern).orElse("");
+ save();
+ }
+
+ @DataBoundSetter
+ public void setLogBuildCause(boolean logBuildCause) {
+ this.logBuildCause = logBuildCause;
+ save();
+ }
+
+ /**
+ * @deprecated as of 2.6
+ **/
+ @Deprecated
public DescriptorExtensionList> getLoggerDescriptors() {
- return Jenkins.getInstance().getDescriptorList(AuditLogger.class);
+ return AuditLogger.all();
}
+ @DataBoundSetter
+ public void setLoggers(List loggers) {
+ this.loggers = Optional.ofNullable(loggers).orElse(Collections.emptyList());
+ }
+ @PostConstruct
private void applySettings() {
try {
AuditTrailFilter.setPattern(pattern);
+ } catch (PatternSyntaxException ex) {
+ ex.printStackTrace();
}
- catch (PatternSyntaxException ex) { ex.printStackTrace(); }
for (AuditLogger logger : loggers) {
logger.configure();
@@ -100,82 +129,38 @@ private void applySettings() {
started = true;
}
- /* package */ void onStarted(Run run) {
- if (this.started) {
- StringBuilder buf = new StringBuilder(100);
- for (CauseAction action : run.getActions(CauseAction.class)) {
- for (Cause cause : action.getCauses()) {
- if (buf.length() > 0) buf.append(", ");
- buf.append(cause.getShortDescription());
- }
- }
- if (buf.length() == 0) buf.append("Started");
-
- for (AuditLogger logger : loggers) {
- logger.log(run.getParent().getUrl() + " #" + run.getNumber() + ' ' + buf.toString());
- }
-
- }
+ // TODO keeping this logic while refactoring, I'm not sure this is necessary
+ boolean isStarted() {
+ return started;
}
+ /**
+ * @deprecated as of 2.6
+ **/
+ @Restricted(DoNotUse.class)
+ @Deprecated
public void onFinalized(Run run) {
- if (run instanceof AbstractBuild) {
- onFinalized((AbstractBuild) run);
- }
-
+ LOGGER.warning("AuditTrailPlugin#onFinalized does nothing anymore, please update your script");
}
+ /**
+ * @deprecated as of 2.6
+ **/
+ @Restricted(DoNotUse.class)
+ @Deprecated
public void onFinalized(AbstractBuild build) {
- if (this.started) {
- StringBuilder causeBuilder = new StringBuilder(100);
- for (CauseAction action : build.getActions(CauseAction.class)) {
- for (Cause cause : action.getCauses()) {
- if (causeBuilder.length() > 0) causeBuilder.append(", ");
- causeBuilder.append(cause.getShortDescription());
- }
- }
- if (causeBuilder.length() == 0) causeBuilder.append("Started");
-
- for (AuditLogger logger : loggers) {
- String message = build.getFullDisplayName() +
- " " + causeBuilder.toString() +
- " on node " + buildNodeName(build) +
- " started at " + build.getTimestampString2() +
- " completed in " + build.getDuration() + "ms" +
- " completed: " + build.getResult();
- logger.log(message);
- }
-
- }
- }
-
- private String buildNodeName(AbstractBuild build) {
- Node node = build.getBuiltOn();
- if (node != null) {
- return node.getDisplayName();
- }
-
- return "#unknown#";
+ LOGGER.warning("AuditTrailPlugin#onFinalized does nothing anymore, please update your script");
}
- /* package */ void onRequest(String uri, String extra, String username) {
- if (this.started) {
- for (AuditLogger logger : loggers) {
- logger.log(uri + extra + " by " + username);
- }
- }
- }
-
-
/**
* Backward compatibility
*/
private Object readResolve() {
if (log != null) {
if (loggers == null) {
- loggers = new ArrayList();
+ loggers = new ArrayList<>();
}
- LogFileAuditLogger logger = new LogFileAuditLogger(log, limit, count);
+ LogFileAuditLogger logger = new LogFileAuditLogger(log, 1, 1);
if (!loggers.contains(logger))
loggers.add(logger);
log = null;
@@ -192,11 +177,10 @@ public FormValidation doRegexCheck(@QueryParameter final String value)
try {
Pattern.compile(value);
return FormValidation.ok();
- }
- catch (Exception ex) {
+ } catch (Exception ex) {
return FormValidation.errorWithMarkup("Invalid regular expression (" + ex.getMessage() + ")");
+ + "http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html"
+ + "\">regular expression (" + ex.getMessage() + ")");
}
}
diff --git a/src/main/java/hudson/plugins/audit_trail/AuditTrailRunListener.java b/src/main/java/hudson/plugins/audit_trail/AuditTrailRunListener.java
index ce043eb..8631b38 100644
--- a/src/main/java/hudson/plugins/audit_trail/AuditTrailRunListener.java
+++ b/src/main/java/hudson/plugins/audit_trail/AuditTrailRunListener.java
@@ -1,34 +1,79 @@
package hudson.plugins.audit_trail;
import hudson.Extension;
+import hudson.model.AbstractBuild;
+import hudson.model.Cause;
+import hudson.model.CauseAction;
+import hudson.model.Node;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
-import jenkins.model.Jenkins;
+
+import javax.inject.Inject;
/**
* @author Nicolas De Loof
+ * @author Pierre Beitz
*/
@Extension
public class AuditTrailRunListener extends RunListener {
+ @Inject
+ AuditTrailPlugin configuration;
+
public AuditTrailRunListener() {
super(Run.class);
}
@Override
public void onStarted(Run run, TaskListener listener) {
- AuditTrailPlugin plugin = (AuditTrailPlugin) Jenkins.getInstance().getPlugin("audit-trail");
- if (plugin != null) {
- plugin.onStarted(run);
+ if (configuration.isStarted()) {
+ StringBuilder buf = new StringBuilder(100);
+ for (CauseAction action : run.getActions(CauseAction.class)) {
+ for (Cause cause : action.getCauses()) {
+ if (buf.length() > 0) buf.append(", ");
+ buf.append(cause.getShortDescription());
+ }
+ }
+ if (buf.length() == 0) buf.append("Started");
+
+ for (AuditLogger logger : configuration.getLoggers()) {
+ logger.log(run.getParent().getUrl() + " #" + run.getNumber() + ' ' + buf.toString());
+ }
}
}
@Override
public void onFinalized(Run run) {
- AuditTrailPlugin plugin = (AuditTrailPlugin) Jenkins.getInstance().getPlugin("audit-trail");
- if (plugin != null) {
- plugin.onFinalized(run);
+ if (configuration.isStarted()) {
+ StringBuilder causeBuilder = new StringBuilder(100);
+ for (CauseAction action : run.getActions(CauseAction.class)) {
+ for (Cause cause : action.getCauses()) {
+ if (causeBuilder.length() > 0) causeBuilder.append(", ");
+ causeBuilder.append(cause.getShortDescription());
+ }
+ }
+ if (causeBuilder.length() == 0) causeBuilder.append("Started");
+
+ for (AuditLogger logger : configuration.getLoggers()) {
+ String message = run.getFullDisplayName() +
+ " " + causeBuilder.toString() +
+ " on node " + buildNodeName(run) +
+ " started at " + run.getTimestampString2() +
+ " completed in " + run.getDuration() + "ms" +
+ " completed: " + run.getResult();
+ logger.log(message);
+ }
+ }
+ }
+
+ private String buildNodeName(Run run) {
+ if (run instanceof AbstractBuild) {
+ Node node = ((AbstractBuild) run).getBuiltOn();
+ if (node != null) {
+ return node.getDisplayName();
+ }
}
+ return "#unknown#";
}
}
diff --git a/src/main/resources/hudson/plugins/audit_trail/AuditTrailPlugin/config.jelly b/src/main/resources/hudson/plugins/audit_trail/AuditTrailPlugin/config.jelly
index c7e3d6d..e7bbff0 100644
--- a/src/main/resources/hudson/plugins/audit_trail/AuditTrailPlugin/config.jelly
+++ b/src/main/resources/hudson/plugins/audit_trail/AuditTrailPlugin/config.jelly
@@ -2,17 +2,18 @@
+
-
+
-
+
diff --git a/src/test/java/hudson/plugins/audit_trail/AuditTrailTest.java b/src/test/java/hudson/plugins/audit_trail/AuditTrailTest.java
index 4885b60..72c1050 100644
--- a/src/test/java/hudson/plugins/audit_trail/AuditTrailTest.java
+++ b/src/test/java/hudson/plugins/audit_trail/AuditTrailTest.java
@@ -30,7 +30,8 @@
import hudson.Util;
import hudson.model.Cause;
import hudson.model.FreeStyleProject;
-import jenkins.model.Jenkins;
+import jenkins.model.GlobalConfiguration;
+
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
@@ -84,7 +85,7 @@ public void shouldGenerateTwoAuditLogs() throws Exception {
form.getInputByName(LOG_FILE_COUNT_INPUT_NAME).setValueAttribute("2");
j.submit(form);
- AuditTrailPlugin plugin = Jenkins.getInstance().getPlugin(AuditTrailPlugin.class);
+ AuditTrailPlugin plugin = GlobalConfiguration.all().get(AuditTrailPlugin.class);
LogFileAuditLogger logger = (LogFileAuditLogger) plugin.getLoggers().get(0);
assertEquals("log path", logFile.getPath(), logger.getLog());
assertEquals("log size", 1, logger.getLimit());
diff --git a/src/test/java/hudson/plugins/audit_trail/ConfigurationAsCodeTest.java b/src/test/java/hudson/plugins/audit_trail/ConfigurationAsCodeTest.java
new file mode 100644
index 0000000..9c89b9e
--- /dev/null
+++ b/src/test/java/hudson/plugins/audit_trail/ConfigurationAsCodeTest.java
@@ -0,0 +1,73 @@
+package hudson.plugins.audit_trail;
+
+import hudson.ExtensionList;
+import io.jenkins.plugins.casc.ConfigurationContext;
+import io.jenkins.plugins.casc.ConfiguratorRegistry;
+import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
+import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
+import io.jenkins.plugins.casc.model.CNode;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.jvnet.hudson.test.Issue;
+
+import static io.jenkins.plugins.casc.misc.Util.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+/**
+ * Created by Pierre Beitz
+ * on 2019-07-20.
+ */
+public class ConfigurationAsCodeTest {
+
+ @ClassRule
+ @ConfiguredWithCode("jcasc.yml")
+ public static JenkinsConfiguredWithCodeRule r = new JenkinsConfiguredWithCodeRule();
+
+ @Issue("JENKINS-57232")
+ @Test
+ public void should_support_configuration_as_code() {
+ ExtensionList extensionList = r.jenkins.getExtensionList(AuditTrailPlugin.class);
+ AuditTrailPlugin plugin = extensionList.get(0);
+ assertEquals(".*/(?:configSubmit|doUninstall|doDelete|postBuildResult|enable|disable|cancelQueue|stop|toggleLogKeep|doWipeOutWorkspace|createItem|createView|toggleOffline|cancelQuietDown|quietDown|restart|exit|safeExit)", plugin.getPattern());
+ assertTrue(plugin.getLogBuildCause());
+ assertEquals(3, plugin.getLoggers().size());
+
+ //first logger
+ AuditLogger logger = plugin.getLoggers().get(0);
+ assertTrue(logger instanceof ConsoleAuditLogger);
+ assertEquals("test", ((ConsoleAuditLogger) logger).getLogPrefix());
+ assertEquals(ConsoleAuditLogger.Output.STD_OUT, ((ConsoleAuditLogger) logger).getOutput());
+ assertEquals("yyyy-MM-dd HH:mm:ss:SSS", ((ConsoleAuditLogger) logger).getDateFormat());
+
+ //second logger
+ logger = plugin.getLoggers().get(1);
+ assertTrue(logger instanceof LogFileAuditLogger);
+ assertEquals(10, ((LogFileAuditLogger) logger).getCount());
+ assertEquals(666, ((LogFileAuditLogger) logger).getLimit());
+ assertEquals("/log/location", ((LogFileAuditLogger) logger).getLog());
+
+ //third logger
+ logger = plugin.getLoggers().get(2);
+ assertEquals("jenkins", ((SyslogAuditLogger) logger).getAppName());
+ assertEquals("DAEMON", ((SyslogAuditLogger) logger).getFacility());
+ assertEquals("RFC_5424", ((SyslogAuditLogger) logger).getMessageFormat());
+ assertEquals("hostname", ((SyslogAuditLogger) logger).getMessageHostname());
+ assertEquals("syslog-server", ((SyslogAuditLogger) logger).getSyslogServerHostname());
+ assertEquals(514, ((SyslogAuditLogger) logger).getSyslogServerPort());
+ }
+
+ @Issue("JENKINS-57232")
+ @Test
+ public void should_support_configuration_export() throws Exception {
+ ConfiguratorRegistry registry = ConfiguratorRegistry.get();
+ ConfigurationContext context = new ConfigurationContext(registry);
+ CNode auditTrailAttribute = getUnclassifiedRoot(context).get("audit-trail");
+
+ String exported = toYamlString(auditTrailAttribute);
+
+ String expected = toStringFromYamlFile(this, "expected.yml");
+
+ assertThat(exported, is(expected));
+ }
+}
diff --git a/src/test/java/hudson/plugins/audit_trail/ConsoleAuditLoggerTest.java b/src/test/java/hudson/plugins/audit_trail/ConsoleAuditLoggerTest.java
index 520dcf6..33a7a01 100644
--- a/src/test/java/hudson/plugins/audit_trail/ConsoleAuditLoggerTest.java
+++ b/src/test/java/hudson/plugins/audit_trail/ConsoleAuditLoggerTest.java
@@ -25,7 +25,8 @@
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
-import jenkins.model.Jenkins;
+import jenkins.model.GlobalConfiguration;
+
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
@@ -36,6 +37,7 @@
/**
* @author Tomasz Sęk
+ * @author Pierre Beitz
*/
public class ConsoleAuditLoggerTest {
@@ -58,7 +60,7 @@ public void shouldConfigureConsoleAuditLogger() throws Exception {
// Then
// submit configuration page without any errors
- AuditTrailPlugin plugin = Jenkins.getInstance().getPlugin(AuditTrailPlugin.class);
+ AuditTrailPlugin plugin = GlobalConfiguration.all().get(AuditTrailPlugin.class);
assertEquals("amount of loggers", 1, plugin.getLoggers().size());
AuditLogger logger = plugin.getLoggers().get(0);
assertTrue("ConsoleAuditLogger should be configured", logger instanceof ConsoleAuditLogger);
diff --git a/src/test/resources/hudson/plugins/audit_trail/expected.yml b/src/test/resources/hudson/plugins/audit_trail/expected.yml
new file mode 100644
index 0000000..4443901
--- /dev/null
+++ b/src/test/resources/hudson/plugins/audit_trail/expected.yml
@@ -0,0 +1,18 @@
+logBuildCause: true
+loggers:
+- console:
+ dateFormat: "yyyy-MM-dd HH:mm:ss:SSS"
+ logPrefix: "test"
+ output: STD_OUT
+- logFile:
+ count: 10
+ limit: 666
+ log: "/log/location"
+- syslog:
+ appName: "jenkins"
+ facility: "DAEMON"
+ messageFormat: "RFC_5424"
+ messageHostname: "hostname"
+ syslogServerHostname: "syslog-server"
+ syslogServerPort: 514
+pattern: ".*/(?:configSubmit|doUninstall|doDelete|postBuildResult|enable|disable|cancelQueue|stop|toggleLogKeep|doWipeOutWorkspace|createItem|createView|toggleOffline|cancelQuietDown|quietDown|restart|exit|safeExit)"
diff --git a/src/test/resources/hudson/plugins/audit_trail/jcasc.yml b/src/test/resources/hudson/plugins/audit_trail/jcasc.yml
new file mode 100644
index 0000000..11da7cc
--- /dev/null
+++ b/src/test/resources/hudson/plugins/audit_trail/jcasc.yml
@@ -0,0 +1,20 @@
+unclassified:
+ audit-trail:
+ logBuildCause: true
+ loggers:
+ - console:
+ dateFormat: "yyyy-MM-dd HH:mm:ss:SSS"
+ logPrefix: "test"
+ output: STD_OUT
+ - logFile:
+ count: 10
+ limit: 666
+ log: "/log/location"
+ - syslog:
+ appName: "jenkins"
+ facility: "DAEMON"
+ messageFormat: "RFC_5424"
+ messageHostname: "hostname"
+ syslogServerHostname: "syslog-server"
+ syslogServerPort: 514
+ pattern: ".*/(?:configSubmit|doUninstall|doDelete|postBuildResult|enable|disable|cancelQueue|stop|toggleLogKeep|doWipeOutWorkspace|createItem|createView|toggleOffline|cancelQuietDown|quietDown|restart|exit|safeExit)"