├── doc ├── images │ ├── splunk_for_jenkins_post_job.png │ └── splunk_for_jenkins_config_basic.png └── extension.md ├── splunk-devops └── src │ ├── test │ ├── resources │ │ ├── splunk_metadata.properties │ │ ├── com │ │ │ └── splunk │ │ │ │ └── splunkjenkins │ │ │ │ ├── CoverageMetricTest │ │ │ │ ├── config.xml │ │ │ │ └── jobs │ │ │ │ │ ├── JaCoCo │ │ │ │ │ ├── workspace │ │ │ │ │ │ ├── jacoco.exec │ │ │ │ │ │ ├── classes │ │ │ │ │ │ │ └── com │ │ │ │ │ │ │ │ └── mycompany │ │ │ │ │ │ │ │ ├── App.class │ │ │ │ │ │ │ │ └── App$Util.class │ │ │ │ │ │ └── java │ │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── mycompany │ │ │ │ │ │ │ └── App.java │ │ │ │ │ └── config.xml │ │ │ │ │ ├── Cobertura │ │ │ │ │ ├── workspace │ │ │ │ │ │ └── coverage.xml │ │ │ │ │ └── config.xml │ │ │ │ │ └── Clover │ │ │ │ │ ├── config.xml │ │ │ │ │ └── workspace │ │ │ │ │ └── clover.xml │ │ │ │ ├── PostBuildGroovyScriptTest.zip │ │ │ │ └── TestResultAdapterTest │ │ │ │ └── jobs │ │ │ │ ├── testng_job1 │ │ │ │ ├── config.xml │ │ │ │ └── workspace │ │ │ │ │ └── testng-reporter-log-result.xml │ │ │ │ └── xunit_job1 │ │ │ │ └── config.xml │ │ └── logging.properties │ └── java │ │ └── com │ │ └── splunk │ │ └── splunkjenkins │ │ ├── SplunkResponse.java │ │ ├── BaseTest.java │ │ ├── JdkSplunkLogHandlerTest.java │ │ ├── TestResultAdapterTest.java │ │ ├── HealthMonitorTest.java │ │ ├── utils │ │ ├── LogEventHelperTest.java │ │ └── TestCaseResultUtilsTest.java │ │ ├── TeeConsoleLogFilterTest.java │ │ ├── CoverageMetricTest.java │ │ ├── SplunkArchiveFileTest.java │ │ └── SplunkLogServiceTest.java │ └── main │ ├── webapp │ ├── images │ │ ├── splunkIcon.png │ │ ├── hec_token_list.png │ │ ├── hec_global_config.png │ │ ├── splunk_logo_black.png │ │ └── splunk_logo_green.png │ └── help-splunkAppUrl.html │ ├── resources │ ├── com │ │ └── splunk │ │ │ └── splunkjenkins │ │ │ ├── SplunkJenkinsInstallation │ │ │ ├── help-retriesOnError.html │ │ │ ├── help-no-splunkAppUrl.html │ │ │ ├── help-maxEventsBatchSize.html │ │ │ ├── help-metadataHost.html │ │ │ ├── help-metadataSource.html │ │ │ ├── help-splunkAppUrl.html │ │ │ ├── config.properties │ │ │ ├── help-rawEventEnabled.html │ │ │ ├── help-delay.html │ │ │ ├── help-indexName.html │ │ │ ├── help-httpInputConfig.html │ │ │ ├── help-host.html │ │ │ ├── help-metaDataConfig.html │ │ │ ├── help-token.html │ │ │ ├── help-ignoredJobs.html │ │ │ ├── help-groovyBinding.html │ │ │ └── config.jelly │ │ │ ├── SplunkArtifactNotifier │ │ │ ├── help-skipGlobalSplunkArchive.html │ │ │ ├── config.properties │ │ │ ├── help-sizeLimit.html │ │ │ ├── help-publishFromSlave.html │ │ │ └── config.jelly │ │ │ ├── listeners │ │ │ └── Messages.properties │ │ │ ├── model │ │ │ └── MetaDataConfigItem │ │ │ │ ├── help-value.html │ │ │ │ ├── help-keyName.html │ │ │ │ ├── help-dataSource.html │ │ │ │ └── config.jelly │ │ │ └── Messages.properties │ ├── sample.groovy │ ├── metadata.properties │ └── junit.xsd │ ├── java │ └── com │ │ └── splunk │ │ └── splunkjenkins │ │ ├── model │ │ ├── TestStatus.java │ │ ├── EmptyTestCaseGroup.java │ │ ├── JunitResultAggregateAdapter.java │ │ ├── EventType.java │ │ ├── LoggingJobExtractor.java │ │ ├── JunitTestCaseGroup.java │ │ ├── JunitResultAdapter.java │ │ ├── AbstractTestResultAdapter.java │ │ ├── TestCaseResult.java │ │ ├── CloverCoverageMetrics.java │ │ ├── CoberturaCoverageMetrics.java │ │ ├── JacocoCoverageMetrics.java │ │ ├── TestNGResultAdapter.java │ │ └── CucumberTestResultAdapter.java │ │ ├── utils │ │ ├── CoverageDetailJsonSerializer.java │ │ ├── SpecialDoubleAdapter.java │ │ ├── SpecialFloatAdapter.java │ │ ├── MultipleHostResolver.java │ │ └── CustomSSLConnectionSocketFactory.java │ │ ├── links │ │ ├── ReportAction.java │ │ ├── HealthLinkAction.java │ │ ├── LinkSplunkAction.java │ │ ├── ComputerLogActionFactory.java │ │ ├── BuildableItemActionFactory.java │ │ └── RunActionFactory.java │ │ ├── listeners │ │ ├── UserSecurityListener.java │ │ ├── LoggingComputerListener.java │ │ ├── LoggingItemListener.java │ │ ├── LoggingQueueListener.java │ │ └── LoggingConfigListener.java │ │ ├── LoggingInitStep.java │ │ ├── Constants.java │ │ ├── SplunkArtifactNotifier.java │ │ └── HealthMonitor.java │ └── groovy │ └── com │ └── splunk │ └── splunkjenkins │ └── UserActionDSL.groovy ├── splunk-devops-extend ├── src │ ├── main │ │ ├── resources │ │ │ ├── com │ │ │ │ └── splunk │ │ │ │ │ └── splunkjenkins │ │ │ │ │ ├── SplunkMessageStep │ │ │ │ │ ├── help-globalScriptEnabled.html │ │ │ │ │ └── config.jelly │ │ │ │ │ ├── SplunkPipelineJobProperty │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help-enableDiagram.html │ │ │ │ │ └── config-details.jelly │ │ │ │ │ ├── SplunkConsoleLogStep │ │ │ │ │ └── config.jelly │ │ │ │ │ └── SplunkLogFileStep │ │ │ │ │ ├── config.properties │ │ │ │ │ └── config.jelly │ │ │ └── index.jelly │ │ └── java │ │ │ └── com │ │ │ └── splunk │ │ │ └── splunkjenkins │ │ │ ├── SplunkPipelineJobProperty.java │ │ │ ├── SplunkinsDslVariable.java │ │ │ ├── SplunkConsoleLogStep.java │ │ │ ├── PipelineGraphVizSupport.java │ │ │ ├── SplunkLogFileStep.java │ │ │ └── PipelineRunSupport.java │ └── test │ │ └── java │ │ └── com │ │ └── splunk │ │ └── splunkjenkins │ │ ├── SplunkinsDslVariableTest.java │ │ ├── SplunkLogFileStepTest.java │ │ ├── SplunkConsoleLogStepTest.java │ │ ├── PipelineExecuteDiagramTest.java │ │ └── StageStepNodesTest.java └── pom.xml ├── readme.md ├── .gitignore ├── Jenkinsfile └── splunk-devops-shaded └── pom.xml /doc/images/splunk_for_jenkins_post_job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/doc/images/splunk_for_jenkins_post_job.png -------------------------------------------------------------------------------- /doc/images/splunk_for_jenkins_config_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/doc/images/splunk_for_jenkins_config_basic.png -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/splunk_metadata.properties: -------------------------------------------------------------------------------- 1 | source=unit_test 2 | host=dev 3 | sourcetype=json:jenkins 4 | sourcetype_text=text:jenkins -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /splunk-devops/src/main/webapp/images/splunkIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/main/webapp/images/splunkIcon.png -------------------------------------------------------------------------------- /splunk-devops/src/main/webapp/help-splunkAppUrl.html: -------------------------------------------------------------------------------- 1 |

Please configure the URL for splunk_app_jenkins in 2 | Splunk plugin configure advance section 3 |

-------------------------------------------------------------------------------- /splunk-devops/src/main/webapp/images/hec_token_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/main/webapp/images/hec_token_list.png -------------------------------------------------------------------------------- /splunk-devops/src/main/webapp/images/hec_global_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/main/webapp/images/hec_global_config.png -------------------------------------------------------------------------------- /splunk-devops/src/main/webapp/images/splunk_logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/main/webapp/images/splunk_logo_black.png -------------------------------------------------------------------------------- /splunk-devops/src/main/webapp/images/splunk_logo_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/main/webapp/images/splunk_logo_green.png -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkMessageStep/help-globalScriptEnabled.html: -------------------------------------------------------------------------------- 1 |
2 | Run the customized command in the plugin config page 3 |
-------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkPipelineJobProperty/help.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Enable sending pipeline execution diagram by default 4 |

5 |
-------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Splunk for Jenkins 2 | --------- 3 | 4 | ### Moved to https://github.com/jenkinsci/splunk-devops-plugin as [a Jenkins plugin hosting requirement](https://jenkins.io/doc/developer/publishing/requesting-hosting/) 5 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-retriesOnError.html: -------------------------------------------------------------------------------- 1 |
2 |

The number of times the plugin will try to send data to Splunk before giving up.

3 |
4 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkConsoleLogStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | Forwarding pipeline console log to Splunk 4 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-no-splunkAppUrl.html: -------------------------------------------------------------------------------- 1 |

Please configure the URL for splunk_app_jenkins in 2 | Splunk plugin configure advance section 3 |

-------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/PostBuildGroovyScriptTest.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/test/resources/com/splunk/splunkjenkins/PostBuildGroovyScriptTest.zip -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-maxEventsBatchSize.html: -------------------------------------------------------------------------------- 1 |
2 |

The buffer size of the batch of events to send to Splunk. The default value is 262144(256KB).

3 |
4 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-metadataHost.html: -------------------------------------------------------------------------------- 1 |
2 | Jenkins master hostname, used in Splunk query 3 | 4 | search host="servername" 5 | 6 |
-------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 5 |
6 | This plugin extract pipeline job stages information 7 |
8 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkPipelineJobProperty/help-enableDiagram.html: -------------------------------------------------------------------------------- 1 |
2 | pipeline execution diagram is described in graphviz dot format, see also 3 | http://graphviz.org/documentation/ 4 |
-------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-metadataSource.html: -------------------------------------------------------------------------------- 1 |
2 | Event source name, where the event originated, used in Splunk query 3 | 4 | search source="sourcename" 5 | 6 |
-------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/jacoco.exec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/jacoco.exec -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkArtifactNotifier/help-skipGlobalSplunkArchive.html: -------------------------------------------------------------------------------- 1 |
2 | To skip the global post job archiving DSL e.g. 3 | 4 | archive("**/*.log") 5 | 6 | when the DSL does not fit for specific set of job. 7 |
-------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-splunkAppUrl.html: -------------------------------------------------------------------------------- 1 |

2 | The Splunk App for Jenkins host address, e.g. 3 | http://hostname:port/en-US/app/splunk_app_jenkins/
4 |

-------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/config.properties: -------------------------------------------------------------------------------- 1 | ConfigTitle=Splunk for Jenkins Configuration 2 | Hostname=Splunk Host Name 3 | default_metadata=\ 4 | host={0}\ 5 | #audit trail is not enabled by default\n\ 6 | jenkins_config.enabled=false 7 | #end of metadata -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/classes/com/mycompany/App.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/classes/com/mycompany/App.class -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-rawEventEnabled.html: -------------------------------------------------------------------------------- 1 |
2 |

HTTP Event Collector supports arbitrary data formats similar to Splunk forwarders, 3 | relying on line-breaking rules etc. Supported in Splunk 6.3.1511 and later release 4 |

5 |
6 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/classes/com/mycompany/App$Util.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splunk/splunkforjenkins/HEAD/splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/classes/com/mycompany/App$Util.class -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | handlers=java.util.logging.FileHandler 2 | java.util.logging.FileHandler.pattern=debug.log 3 | java.util.logging.FileHandler.level=ALL 4 | com.splunk.splunkjenkins.level=FINEST 5 | org.apache.http.level = ALL 6 | java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-delay.html: -------------------------------------------------------------------------------- 1 |
2 |

Schedules the specified task for repeated fixed-rate execution beginning after the specified delay. Subsequent 3 | executions take place at approximately regular intervals, separated by the specified period.

4 |
5 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/TestStatus.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | /** 4 | * TestNG used PASS,FAIL,SKIP, Junit(CaseResult.Status) used passed,skipped,pass,failed,fixed,regression 5 | * collapse them into 3 (passed, failure, skipped) 6 | */ 7 | public enum TestStatus { 8 | PASSED, FAILURE, SKIPPED 9 | } 10 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-indexName.html: -------------------------------------------------------------------------------- 1 |
2 |

The index in Splunk to which the events will be indexed to. Defaults to "main" index in Splunk. Note: If using a 3 | custom index, that index must be already exist on your Splunk instance. Splunk-Jenkins will not create it for 4 | you.

5 |
6 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkLogFileStep/config.properties: -------------------------------------------------------------------------------- 1 | ant_pattern=\ 2 | You can use wildcards like "{1}" \ 3 | See \ 4 | the {0} attribute of Ant fileset for the exact format.\ 5 | The base directory is the workspace.\ 6 | You can only archive files that are located in your workspace. -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkArtifactNotifier/config.properties: -------------------------------------------------------------------------------- 1 | ant_pattern=\ 2 | You can use wildcards like "{1}" \ 3 | See \ 4 | the {0} attribute of Ant fileset for the exact format.\ 5 | The base directory is the workspace.\ 6 | You can only archive files that are located in your workspace. -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/sample.groovy: -------------------------------------------------------------------------------- 1 | //send job metadata and junit reports with page size set to 50 (each event contains max 50 test cases) 2 | splunkins.sendTestReport(50) 3 | //send coverage, each event contains max 50 class metrics 4 | splunkins.sendCoverageReport(50) 5 | //send all logs from workspace to splunk, with each file size limits to 10MB 6 | splunkins.archive("**/*.log", null, false, "10MB") 7 | 8 | //end -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkArtifactNotifier/help-sizeLimit.html: -------------------------------------------------------------------------------- 1 |
2 | Limit the single file size to prevent publishing the whole huge log file generated accidentally by some program and uses up 3 | your Splunk daily volume license. The plugin will log a "file truncated to size:xx" event in Splunk when size limit is reached 4 | and will stop publishing the remaining content. 5 |
-------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkPipelineJobProperty/config-details.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | work 3 | 4 | # Vim junk files 5 | .*.swp 6 | *~ 7 | 8 | # IntelliJ project files 9 | .idea/ 10 | *.iml 11 | 12 | # Eclipse IDE project files 13 | .classpath 14 | .project 15 | .settings/ 16 | /splunkjenkins/nbproject/ 17 | 18 | #debug log 19 | debug.log 20 | debug.log.lck 21 | 22 | # OS X 23 | .DS_Store 24 | 25 | # mvn versions:set 26 | pom.xml.versionsBackup 27 | pom.xml.releaseBackup 28 | dependency-reduced-pom.xml 29 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/listeners/Messages.properties: -------------------------------------------------------------------------------- 1 | audit.abort_job=aborted job {0} 2 | audit.start_job=started job {0} 3 | audit.create_item=created {0} 4 | audit.rename_item=renamed {0} to {1} 5 | audit.update_item=updated {0} 6 | audit.delete_item=deleted {0} 7 | audit.cloned_item=cloned item {0} from {1} 8 | audit.user_fail_login=failed to login 9 | audit.user_fail_auth=failed to authenticate 10 | audit.user_logout=logged out 11 | audit.user_login=logged in -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/metadata.properties: -------------------------------------------------------------------------------- 1 | source=jenkins 2 | #for new type not specified with x.index=y 3 | index=jenkins_statistics 4 | #default index and source type settings 5 | build_report.index=jenkins 6 | build_event.index=jenkins_statistics 7 | queue_info.index=jenkins_statistics 8 | jenkins_config.index=jenkins_statistics 9 | slave_info.index=jenkins_statistics 10 | console_log.index=jenkins_console 11 | file.index=jenkins_artifact 12 | sourcetype=json:jenkins 13 | sourcetype_text=text:jenkins 14 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkMessageStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/model/MetaDataConfigItem/help-value.html: -------------------------------------------------------------------------------- 1 |
2 | The event can be turned off by setting it to Disabled 3 | Index is a data repository in Splunk, you can set a different data retention policy and access privileges for each 4 | index in Splunk. 5 | Source Type is used by Splunk to determine how incoming data is formatted. 6 | It is recommended to use the plugin's default config if you are using Splunk App for Jenkins as the App expects a certain metadata format. 7 |
-------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/SplunkResponse.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public class SplunkResponse { 7 | List entry; 8 | 9 | public String getFirst(String key) { 10 | return getItem(0, key); 11 | } 12 | 13 | public void setEntry(List entry) { 14 | this.entry = entry; 15 | } 16 | 17 | public String getItem(int idx, String key) { 18 | return entry.get(idx).content.get(key).toString(); 19 | } 20 | 21 | public static class EntryItem { 22 | Map content; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/model/MetaDataConfigItem/help-keyName.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | The event can be turned off by setting it to Disabled.
4 | 5 | Index is a data repository in Splunk, you can set a different data retention policy and access privileges for 6 | each index in Splunk.
7 | 8 | Source Type is used by Splunk to determine how incoming data is formatted.
9 |

10 | 11 |

It is recommended to use the plugin's default config 12 | if you are using Splunk App for Jenkins as the App expects a certain metadata format. 13 |

14 | 15 |
-------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/workspace/java/com/mycompany/App.java: -------------------------------------------------------------------------------- 1 | package com.mycompany; 2 | 3 | /** 4 | * Hello world! 5 | */ 6 | public class App { 7 | public String getText() { 8 | return "hello"; 9 | } 10 | 11 | public int getResult(boolean even) { 12 | if (even) { 13 | return 2; 14 | } else { 15 | return 1; 16 | } 17 | } 18 | 19 | public boolean isOk() { 20 | return false; 21 | } 22 | 23 | public static class Util { 24 | public static int calc(int a, int b) { 25 | return a + b; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-httpInputConfig.html: -------------------------------------------------------------------------------- 1 |
2 |
You need enable HTTP Event Collector in Splunk.
 3 | To enable it, go to Splunk Settings > Data inputs > HTTP Event Collector.
 4 | Then click the Global Settings button in the upper-right corner.
 5 | You can configure HTTP Port number and SSL on the Global Settings.
 6 | Port is 8088, and SSL is enabled by default.
 7 |     
8 | 9 |

10 | See more details at HTTP Event Collector 11 | walk through 12 |

13 |
14 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-host.html: -------------------------------------------------------------------------------- 1 |
2 |

The Splunk Indexer hostname or IP address, multiple hosts separated by comma. Example: 3 | "192.168.1.4,192.168.1.5"

4 |
    5 |
  • For Splunk cloud user, the host name is something like http-inputs-xx.splunkcloud.com or 6 | http-inputs-xx.cloud.splunk.com, and HTTP Input Port is 443 7 |
  • 8 |
  • For Splunk enterprise user, the host name is the indexer host name, and HTTP Input Port is 8088 by default 9 |
  • 10 |
11 | You need enable "HTTP Event Collector" In Splunk to use the plugin, please checkout 12 | HTTP Event Collector 13 | 14 |
15 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-metaDataConfig.html: -------------------------------------------------------------------------------- 1 |
2 |

Specify index, host, source, soucetype for the events.

3 |

index is a data repository in Splunk, please create the 4 indexes in Splunk: 4 | 5 | jenkins, jenkins_statistics, jenkins_console and jenkins_artifact 6 | 7 |

8 |

9 | host is used to identify which Jenkins master is the source of the data. 10 | the metadata can be used in Splunk query language such as
11 | index="jenkins" host="servername" sourcetype="json:jenkins"
12 |

13 | 14 |

15 | See more details 16 |

17 |
18 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/utils/CoverageDetailJsonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | import com.splunk.splunkjenkins.model.CoverageMetricsAdapter; 4 | import shaded.splk.com.google.gson.JsonElement; 5 | import shaded.splk.com.google.gson.JsonSerializationContext; 6 | import shaded.splk.com.google.gson.JsonSerializer; 7 | 8 | import java.lang.reflect.Type; 9 | 10 | public class CoverageDetailJsonSerializer implements JsonSerializer { 11 | @Override 12 | public JsonElement serialize(CoverageMetricsAdapter.CoverageDetail coverageDetail, Type type, 13 | JsonSerializationContext jsonSerializationContext) { 14 | return jsonSerializationContext.serialize(coverageDetail.getReport()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/links/ReportAction.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.links; 2 | 3 | import com.splunk.splunkjenkins.Messages; 4 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 5 | import hudson.Extension; 6 | import hudson.model.RootAction; 7 | 8 | @SuppressWarnings("unused") 9 | @Extension 10 | public class ReportAction implements RootAction { 11 | @Override 12 | public String getIconFileName() { 13 | return Messages.SplunkIconName(); 14 | } 15 | 16 | @Override 17 | public String getDisplayName() { 18 | return "Splunk"; 19 | } 20 | 21 | @Override 22 | public String getUrlName() { 23 | SplunkJenkinsInstallation instance = SplunkJenkinsInstallation.get(); 24 | return instance.getAppUrlOrHelp() + "overview?overview_jenkinsmaster=" + instance.getMetadataHost(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/links/HealthLinkAction.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.links; 2 | 3 | import com.splunk.splunkjenkins.Messages; 4 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 5 | import hudson.Extension; 6 | import hudson.model.ManagementLink; 7 | 8 | @SuppressWarnings("unused") 9 | @Extension 10 | public class HealthLinkAction extends ManagementLink { 11 | @Override 12 | public String getIconFileName() { 13 | return Messages.SplunkIconName(); 14 | } 15 | 16 | @Override 17 | public String getDisplayName() { 18 | return "Jenkins Health"; 19 | } 20 | 21 | @Override 22 | public String getUrlName() { 23 | SplunkJenkinsInstallation instance = SplunkJenkinsInstallation.get(); 24 | return instance.getAppUrlOrHelp() + "jenkins_health?form.hostname=" + instance.getMetadataHost(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-token.html: -------------------------------------------------------------------------------- 1 |
2 |

You can find the HTTP Event Collector Token in Splunk, go to Splunk Settings > Data inputs > HTTP Event 3 | Collector. 4 |

5 | 6 |

7 | See more details at HTTP Event Collector 8 | walk through 9 |

10 |

To verify the token via curl command

11 |
12 | hec_host=<splunk-host>
13 | hec_port=8088
14 | hec_token=<splunk-token>
15 | curl -k "https://${hec_host}:${hec_port}/services/collector/event" -H "Authorization: Splunk ${hec_token}" -d \
16 | '{"host":"test-host","index":"jenkins_console","sourcetype":"json:jenkins","source":"logger://dummy","event":{"level":"INFO","log_source":"cmdline","message":"Test HEC"}}'
17 | 
18 |     
19 |
20 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkArtifactNotifier/help-publishFromSlave.html: -------------------------------------------------------------------------------- 1 |
2 | Publish log files directly from the slave, instead of proxy for the process to the master. 3 | When publish from slave is selected, Jenkins master will transfer the plugin and its dependence to slave and 4 | initiate 5 | the publishing process from the slave. 6 | Take below into consideration: 7 |
    8 |
  • slave and master load 9 |
  • 10 |
  • 11 | log file size 12 |
  • 13 |
  • 14 | slave type, long lived slave or one time use slave 15 |
  • 16 |
17 | Rule of thumb for selecting publish type: 18 | 19 |
    20 |
  • a. if log files size is less than 5MB, publish from master is preferred.
  • 21 |
  • b. if Splunk instance is in an isolated network which is not reachable from slave, you need publish from 22 | master. 23 |
  • 24 |
25 | 26 |
27 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.splunk.splunkjenkins.utils.SplunkLogService; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Rule; 7 | import org.jvnet.hudson.test.JenkinsRule; 8 | 9 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 10 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getDefaultDslScript; 11 | 12 | public class BaseTest { 13 | @Rule 14 | public JenkinsRule j = new JenkinsRule(); 15 | 16 | @Before 17 | public void setUp() throws Exception { 18 | org.junit.Assume.assumeTrue(checkTokenAvailable()); 19 | SplunkJenkinsInstallation.get().setScriptContent(getDefaultDslScript()); 20 | SplunkJenkinsInstallation.get().updateCache(); 21 | } 22 | 23 | @After 24 | public void tearDown() { 25 | SplunkLogService.getInstance().stopWorker(); 26 | SplunkLogService.getInstance().releaseConnection(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/utils/SpecialDoubleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | 4 | import shaded.splk.com.google.gson.TypeAdapter; 5 | import shaded.splk.com.google.gson.stream.JsonReader; 6 | import shaded.splk.com.google.gson.stream.JsonToken; 7 | import shaded.splk.com.google.gson.stream.JsonWriter; 8 | 9 | import java.io.IOException; 10 | 11 | public class SpecialDoubleAdapter extends TypeAdapter { 12 | @Override 13 | public void write(JsonWriter jsonWriter, Double number) throws IOException { 14 | if (number == null || Double.isNaN(number) || Double.isInfinite(number)) { 15 | jsonWriter.nullValue(); 16 | } else { 17 | jsonWriter.value(number); 18 | } 19 | } 20 | 21 | @Override 22 | public Double read(JsonReader in) throws IOException { 23 | if (in.peek() == JsonToken.NULL) { 24 | in.nextNull(); 25 | return null; 26 | } 27 | return in.nextDouble(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/utils/SpecialFloatAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | 4 | import shaded.splk.com.google.gson.TypeAdapter; 5 | import shaded.splk.com.google.gson.stream.JsonReader; 6 | import shaded.splk.com.google.gson.stream.JsonToken; 7 | import shaded.splk.com.google.gson.stream.JsonWriter; 8 | 9 | import java.io.IOException; 10 | 11 | public class SpecialFloatAdapter extends TypeAdapter { 12 | @Override 13 | public void write(JsonWriter jsonWriter, Float number) throws IOException { 14 | if (number == null || Float.isNaN(number) || Float.isInfinite(number)) { 15 | jsonWriter.nullValue(); 16 | } else { 17 | jsonWriter.value(number); 18 | } 19 | } 20 | 21 | @Override 22 | public Float read(JsonReader in) throws IOException { 23 | if (in.peek() == JsonToken.NULL) { 24 | in.nextNull(); 25 | return null; 26 | } 27 | return (float) in.nextDouble(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/links/LinkSplunkAction.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.links; 2 | 3 | 4 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 5 | import hudson.model.Action; 6 | 7 | import com.splunk.splunkjenkins.Messages; 8 | 9 | public class LinkSplunkAction implements Action { 10 | String query; 11 | String page; 12 | String displayName; 13 | 14 | public LinkSplunkAction(String tab, String query, String displayName) { 15 | this.query = query; 16 | this.page = tab; 17 | this.displayName = displayName; 18 | } 19 | 20 | @Override 21 | public String getIconFileName() { 22 | return Messages.SplunkIconName(); 23 | } 24 | 25 | @Override 26 | public String getDisplayName() { 27 | return displayName; 28 | } 29 | 30 | @Override 31 | public String getUrlName() { 32 | SplunkJenkinsInstallation instance = SplunkJenkinsInstallation.get(); 33 | return instance.getAppUrlOrHelp() + page + "?" + query; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/links/ComputerLogActionFactory.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.links; 2 | 3 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 4 | import com.splunk.splunkjenkins.utils.LogEventHelper; 5 | import hudson.Extension; 6 | import hudson.model.Action; 7 | import hudson.model.Computer; 8 | import hudson.model.TransientComputerActionFactory; 9 | import jnr.ffi.annotations.Encoding; 10 | 11 | import java.util.Collections; 12 | import java.util.Collection; 13 | 14 | //TODO add agent page and update link 15 | @Extension 16 | public class ComputerLogActionFactory extends TransientComputerActionFactory { 17 | @Override 18 | public Collection createFor(Computer target) { 19 | String query = new LogEventHelper.UrlQueryBuilder() 20 | .putIfAbsent("master", SplunkJenkinsInstallation.get().getMetadataHost()) 21 | .putIfAbsent("slave", target.getName()) 22 | .build(); 23 | return Collections.singleton(new LinkSplunkAction("jenkins_slave", query, "Splunk")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/resources/com/splunk/splunkjenkins/SplunkLogFileStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/utils/MultipleHostResolver.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | import shaded.splk.org.apache.http.conn.DnsResolver; 4 | 5 | import java.net.InetAddress; 6 | import java.net.UnknownHostException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class MultipleHostResolver implements DnsResolver { 11 | public static final String NAME_DELIMITER = ","; 12 | 13 | @Override 14 | public InetAddress[] resolve(final String host) throws UnknownHostException { 15 | if (host == null) { 16 | return null; 17 | } 18 | String hostname = host; 19 | //split by comma 20 | String[] hosts = hostname.split(NAME_DELIMITER); 21 | List addressList = new ArrayList<>(); 22 | for (String endpointHost : hosts) { 23 | InetAddress[] addresses = InetAddress.getAllByName(endpointHost); 24 | for (InetAddress address : addresses) { 25 | addressList.add(address); 26 | } 27 | } 28 | return addressList.toArray(new InetAddress[0]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkArtifactNotifier/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-ignoredJobs.html: -------------------------------------------------------------------------------- 1 |
2 | Check Regular 3 | Expression to select which build will be ignored for monitoring. Build url matches 4 | the pattern will be ignored, for example:
5 | (?:backgroundJobName|adhocJobName|tempJobName) 6 |

will match backgroundJobName, backgroundJobNameBlah, blahbackgroundJobName

7 | ^(?:backgroundJobName|adhocJobName|tempJobName)$ 8 |

will match backgroundJobName but neither backgroundJobNameBlah nor blahbackgroundJobName

9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
(?:X) X, as a non-capturing group
^The beginning of a line
$The end of a line
X|YEither X or Y
\wA word character: [a-zA-Z_0-9]
31 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/EmptyTestCaseGroup.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.tasks.test.TestResult; 4 | 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import static com.splunk.splunkjenkins.Constants.NO_TEST_REPORT_FOUND; 9 | 10 | public class EmptyTestCaseGroup extends JunitTestCaseGroup { 11 | private String message; 12 | 13 | public String getMessage() { 14 | return message; 15 | } 16 | 17 | @Override 18 | public int getFailures() { 19 | return 0; 20 | } 21 | 22 | @Override 23 | public int getPasses() { 24 | return 0; 25 | } 26 | 27 | @Override 28 | public int getSkips() { 29 | return 0; 30 | } 31 | 32 | @Override 33 | public int getTotal() { 34 | return 0; 35 | } 36 | 37 | @Override 38 | public float getDuration() { 39 | return 0; 40 | } 41 | 42 | @Override 43 | public List getTestcase() { 44 | return Collections.emptyList(); 45 | } 46 | 47 | public void setWarning(boolean flag) { 48 | this.message = flag?NO_TEST_REPORT_FOUND:null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/model/MetaDataConfigItem/help-dataSource.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 36 | 37 |
Build Report Junit or other Test Reports sent by calling "send(message)" DSL script 5 |
Build Event Sent when job are started and completed 10 |
Queue Information Basic queue information and Jenkins health metrics 15 |
Console Log Build console log, slave log and Jenkins master log (jenkins.log) 20 |
Log File Artifact contents, send by calling "archive(includes, excludes)" DSL script 25 |
Slave Information The slave(agent) monitor data 30 |
Jenkins Config The contents of Jenkins configuration items, e.g. config.xml, sent when the config file get updated. 35 |
38 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/JunitResultAggregateAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.Extension; 4 | import hudson.tasks.junit.CaseResult; 5 | import hudson.tasks.junit.SuiteResult; 6 | import hudson.tasks.test.AggregatedTestResultAction; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Extension(optional = true) 12 | public class JunitResultAggregateAdapter extends AbstractTestResultAdapter { 13 | @Override 14 | public List getTestResult(AggregatedTestResultAction resultAction) { 15 | List caseResults = new ArrayList<>(); 16 | for (AggregatedTestResultAction.ChildReport childReport : resultAction.getChildReports()) { 17 | if (childReport.result instanceof hudson.tasks.junit.TestResult) { 18 | hudson.tasks.junit.TestResult testResult = (hudson.tasks.junit.TestResult) childReport.result; 19 | for (SuiteResult suite : testResult.getSuites()) { 20 | for (CaseResult testCase : suite.getCases()) { 21 | caseResults.add(testCase); 22 | } 23 | } 24 | } 25 | } 26 | return caseResults; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/links/BuildableItemActionFactory.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.links; 2 | 3 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 4 | import com.splunk.splunkjenkins.utils.LogEventHelper; 5 | import hudson.Extension; 6 | import hudson.Util; 7 | import hudson.model.AbstractProject; 8 | import hudson.model.Action; 9 | import hudson.model.BuildableItem; 10 | import jenkins.model.TransientActionFactory; 11 | 12 | import javax.annotation.Nonnull; 13 | import java.util.Collection; 14 | import java.util.Collections; 15 | 16 | @SuppressWarnings("unused") 17 | @Extension 18 | public class BuildableItemActionFactory extends TransientActionFactory { 19 | @Override 20 | public Class type() { 21 | return BuildableItem.class; 22 | } 23 | 24 | @Nonnull 25 | @Override 26 | public Collection createFor(@Nonnull BuildableItem target) { 27 | String query = new LogEventHelper.UrlQueryBuilder() 28 | .putIfAbsent("build_analysis_jenkinsmaster", SplunkJenkinsInstallation.get().getMetadataHost()) 29 | .putIfAbsent("build_analysis_job", target.getFullName()).build(); 30 | return Collections.singleton(new LinkSplunkAction("build_analysis", query, "Splunk")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/EventType.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | public enum EventType { 4 | BUILD_REPORT(false), 5 | BUILD_EVENT(false), 6 | QUEUE_INFO(false), 7 | JENKINS_CONFIG(false), 8 | CONSOLE_LOG(true), 9 | FILE(true), 10 | SLAVE_INFO(false), 11 | LOG(false), 12 | BATCH_JSON(false); 13 | 14 | /** 15 | * whether the data need to be split by line breaker before send 16 | */ 17 | private boolean needSplit; 18 | 19 | EventType(boolean needSplit) { 20 | this.needSplit = needSplit; 21 | } 22 | 23 | /** 24 | * Need spit the content line by line if raw event not supported 25 | * Only applied for non-structural data, such as file and console text. 26 | * It doesn't applied for json data or xml data 27 | * 28 | * @return true if need spit the contents line by line if raw event not supported; 29 | * false otherwise. 30 | */ 31 | public boolean needSplit() { 32 | return needSplit; 33 | } 34 | 35 | /** 36 | * @param suffix the config metadata, can be either index, source or sourcetype 37 | * @return return name.suffix 38 | */ 39 | public String getKey(String suffix) { 40 | return this.name().toLowerCase() + "." + suffix; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/JdkSplunkLogHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.util.UUID; 7 | import java.util.logging.Handler; 8 | import java.util.logging.Logger; 9 | 10 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class JdkSplunkLogHandlerTest extends BaseTest { 14 | 15 | @Before 16 | public void setUp() throws Exception { 17 | super.setUp(); 18 | LoggingInitStep.registerHandler(); 19 | } 20 | 21 | @Test 22 | public void publish() throws Exception { 23 | Handler[] handlers = Logger.getLogger("").getHandlers(); 24 | boolean found = false; 25 | for (Handler handler : handlers) { 26 | if (handler instanceof JdkSplunkLogHandler) { 27 | found = true; 28 | break; 29 | } 30 | } 31 | assertTrue("LoggingInitStep.setupSplunkJenkins() should be called", found); 32 | String message = "test_log_" + UUID.randomUUID(); 33 | Logger.getLogger("test_info_logger").info(message); 34 | Logger.getLogger("test_warning_logger").warning(message); 35 | verifySplunkSearchResult(message + " level=WARNING", 1); 36 | verifySplunkSearchResult(message + " level=INFO", 1); 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/TestResultAdapterTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import hudson.model.FreeStyleProject; 4 | import hudson.model.Run; 5 | import org.junit.Test; 6 | import org.jvnet.hudson.test.recipes.LocalData; 7 | 8 | import java.io.IOException; 9 | import java.util.UUID; 10 | import java.util.concurrent.ExecutionException; 11 | 12 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 13 | 14 | public class TestResultAdapterTest extends BaseTest { 15 | @LocalData 16 | @Test 17 | public void verifyTestNG() throws ExecutionException, InterruptedException, IOException { 18 | String query = "ExampleIntegrationTest| spath | search \"testsuite.testcase{}.classname\"=ExampleIntegrationTest"; 19 | FreeStyleProject project = (FreeStyleProject) j.getInstance().getItem("testng_job1"); 20 | String jobName = UUID.randomUUID().toString(); 21 | project.renameTo(jobName); 22 | long startTime = System.currentTimeMillis(); 23 | Run run = project.scheduleBuild2(0).get(); 24 | verifySplunkSearchResult(query, startTime, 1); 25 | //verify test_summary.total number 26 | String buildUrl = run.getUrl(); 27 | query = "type=completed test_summary build_url=\"" + buildUrl + "\"| spath | search test_summary.total=2"; 28 | verifySplunkSearchResult(query, startTime, 1); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | // Parameters to run test 3 | properties([ 4 | parameters([string(defaultValue: '', description: 'Splunk host', name: 'host') 5 | , string(defaultValue: '8089', description: 'Splunk management port', name: 'port') 6 | , string(defaultValue: '', description: 'Username', name: 'username') 7 | , string(defaultValue: '', description: 'Password', name: 'password') 8 | , string(defaultValue: '', description: 'Local Repo Url', name: 'repoUrl') 9 | ]), 10 | [$class: 'jenkins.model.BuildDiscarderProperty', strategy: [$class : 'LogRotator', 11 | numToKeepStr : '50', 12 | artifactNumToKeepStr: '20']] 13 | ]) 14 | 15 | node { 16 | checkout scm; 17 | def mvnHome = tool name: 'default', type: 'hudson.tasks.Maven$MavenInstallation' 18 | def mvnCmd = "${mvnHome}/bin/mvn"; 19 | if (params.password) { 20 | mvnCmd += " -Dhost=${params.host} -Dport=${params.port} -Dpassword=${params.password} -Dusername=${params.username}" 21 | } 22 | mvnCmd += " -Djava.net.preferIPv4Stack=true clean verify" 23 | 24 | if (params.repoUrl) { 25 | mvnCmd += " -Plocal -Drepos.url=${params.repoUrl} deploy cobertura:cobertura" 26 | } 27 | sh mvnCmd 28 | } 29 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/TestResultAdapterTest/jobs/testng_job1/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | true 9 | false 10 | false 11 | false 12 | 13 | false 14 | 15 | 16 | touch testng-reporter-log-result.xml 17 | 18 | 19 | 20 | 21 | testng-reporter-log-result.xml 22 | true 23 | true 24 | false 25 | false 26 | 100 27 | 0 28 | 100 29 | 100 30 | 2 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/HealthMonitorTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import hudson.model.FreeStyleProject; 4 | import hudson.model.Label; 5 | import hudson.model.PeriodicWork; 6 | import hudson.model.TaskListener; 7 | import org.junit.Test; 8 | import org.jvnet.hudson.test.TouchBuilder; 9 | 10 | import java.util.UUID; 11 | 12 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 13 | import static org.junit.Assert.*; 14 | 15 | public class HealthMonitorTest extends BaseTest { 16 | 17 | 18 | @Test 19 | public void execute() throws Exception { 20 | HealthMonitor monitor = PeriodicWork.all().get(HealthMonitor.class); 21 | FreeStyleProject p = j.createFreeStyleProject("test-sleep" + UUID.randomUUID()); 22 | p.setAssignedLabel(Label.get("no-such-node")); 23 | p.getBuildersList().add(new TouchBuilder()); 24 | long startTime = System.currentTimeMillis(); 25 | p.scheduleBuild2(0); 26 | monitor.lastAccessTime=0; 27 | monitor.execute(TaskListener.NULL); 28 | verifySplunkSearchResult("event_tag=queue", startTime, 1); 29 | verifySplunkSearchResult("event_tag=slave", startTime, 1); 30 | } 31 | 32 | @Test 33 | public void getRecurrencePeriod() throws Exception { 34 | long userDefault = 45000; 35 | long period = PeriodicWork.all().get(HealthMonitor.class).getRecurrencePeriod(); 36 | assertEquals(userDefault, period); 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/utils/CustomSSLConnectionSocketFactory.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | import shaded.splk.org.apache.http.HttpHost; 4 | import shaded.splk.org.apache.http.conn.ssl.SSLConnectionSocketFactory; 5 | import shaded.splk.org.apache.http.protocol.HttpContext; 6 | 7 | import javax.net.ssl.HostnameVerifier; 8 | import javax.net.ssl.SSLContext; 9 | import java.io.IOException; 10 | import java.net.InetSocketAddress; 11 | import java.net.Socket; 12 | 13 | import static com.splunk.splunkjenkins.utils.MultipleHostResolver.NAME_DELIMITER; 14 | 15 | public class CustomSSLConnectionSocketFactory extends SSLConnectionSocketFactory { 16 | 17 | public CustomSSLConnectionSocketFactory(SSLContext sslContext, HostnameVerifier hostnameVerifier) { 18 | super(sslContext, hostnameVerifier); 19 | } 20 | 21 | @Override 22 | public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) throws IOException { 23 | if (host.getHostName().contains(NAME_DELIMITER)) { 24 | HttpHost resolvedHost = new HttpHost(remoteAddress.getHostName(), host.getPort(), host.getSchemeName()); 25 | return super.connectSocket(connectTimeout, socket, resolvedHost, remoteAddress, localAddress, context); 26 | } else{ 27 | return super.connectSocket(connectTimeout, socket, host, remoteAddress, localAddress, context); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/Cobertura/workspace/coverage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | --source 7 | src/main/java 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/java/com/splunk/splunkjenkins/SplunkPipelineJobProperty.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.google.common.base.Objects; 4 | import hudson.Extension; 5 | import jenkins.model.OptionalJobProperty; 6 | import org.jenkinsci.Symbol; 7 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | import org.kohsuke.stapler.DataBoundSetter; 10 | 11 | import javax.annotation.CheckForNull; 12 | 13 | @SuppressWarnings("rawtypes") 14 | public class SplunkPipelineJobProperty extends OptionalJobProperty { 15 | Boolean enableDiagram; 16 | 17 | @DataBoundConstructor 18 | public SplunkPipelineJobProperty() { 19 | } 20 | 21 | @CheckForNull 22 | public Boolean getEnableDiagram() { 23 | return enableDiagram; 24 | } 25 | 26 | @DataBoundSetter 27 | public void setEnableDiagram(Boolean enableDiagram) { 28 | this.enableDiagram = enableDiagram; 29 | } 30 | 31 | public boolean isDiagramEnabled() { 32 | return Boolean.TRUE.equals(enableDiagram); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return Objects.toStringHelper(this) 38 | .add("enableDiagram", enableDiagram) 39 | .toString(); 40 | } 41 | 42 | @Extension 43 | @Symbol("splunkinsJobOption") 44 | public static class DescriptorImpl extends OptionalJobPropertyDescriptor { 45 | @Override 46 | public String getDisplayName() { 47 | return "Opt in data sent to Splunk"; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/LoggingJobExtractor.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.ExtensionList; 4 | import hudson.ExtensionPoint; 5 | import hudson.model.Run; 6 | import org.jvnet.tiger_types.Types; 7 | 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | public abstract class LoggingJobExtractor implements ExtensionPoint { 15 | public final Class targetType; 16 | 17 | public LoggingJobExtractor() { 18 | Type type = Types.getBaseClass(getClass(), LoggingJobExtractor.class); 19 | if (type instanceof ParameterizedType) 20 | targetType = Types.erasure(Types.getTypeArgument(type, 0)); 21 | else 22 | throw new IllegalStateException(getClass() + " uses the raw type for extending LoggingJobExtractor"); 23 | } 24 | 25 | public abstract Map extract(R r, boolean completed); 26 | 27 | /** 28 | * @return Returns all the registered {@link LoggingJobExtractor}s 29 | */ 30 | public static ExtensionList all() { 31 | return ExtensionList.lookup(LoggingJobExtractor.class); 32 | } 33 | 34 | public static List canApply(Run run) { 35 | List extensions = new ArrayList<>(); 36 | for (LoggingJobExtractor extendListener : LoggingJobExtractor.all()) { 37 | if (extendListener.targetType.isInstance(run)) { 38 | extensions.add(extendListener); 39 | } 40 | } 41 | return extensions; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/listeners/UserSecurityListener.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.listeners; 2 | 3 | import hudson.Extension; 4 | import hudson.model.User; 5 | import jenkins.security.SecurityListener; 6 | import org.acegisecurity.userdetails.UserDetails; 7 | 8 | import javax.annotation.Nonnull; 9 | 10 | import static com.splunk.splunkjenkins.utils.LogEventHelper.logUserAction; 11 | 12 | /** 13 | * Note: all the username are user id, not user full name 14 | */ 15 | @Extension 16 | public class UserSecurityListener extends SecurityListener { 17 | @Override 18 | protected void authenticated(@Nonnull UserDetails details) { 19 | logUserAction(details.getUsername(), "authenticated"); 20 | } 21 | 22 | @Override 23 | protected void failedToAuthenticate(@Nonnull String username) { 24 | logUserAction(getFullName(username), Messages.audit_user_fail_auth()); 25 | } 26 | 27 | @Override 28 | protected void loggedIn(@Nonnull String username) { 29 | logUserAction(getFullName(username), Messages.audit_user_login()); 30 | } 31 | 32 | @Override 33 | protected void failedToLogIn(@Nonnull String username) { 34 | //covered by failedToAuthenticate 35 | } 36 | 37 | @Override 38 | protected void loggedOut(@Nonnull String username) { 39 | logUserAction(getFullName(username), Messages.audit_user_logout()); 40 | } 41 | 42 | /** 43 | * @param username 44 | * @return full name 45 | */ 46 | private String getFullName(String username) { 47 | //user may not exists when user failed to login 48 | User user = User.get(username); 49 | return user.getFullName(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/links/RunActionFactory.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.links; 2 | 3 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 4 | import com.splunk.splunkjenkins.utils.LogEventHelper; 5 | import hudson.Extension; 6 | import hudson.model.Action; 7 | import hudson.model.Job; 8 | import hudson.model.Run; 9 | import jenkins.model.TransientActionFactory; 10 | 11 | import javax.annotation.Nonnull; 12 | import java.io.File; 13 | import java.util.Collection; 14 | import java.util.Collections; 15 | 16 | @SuppressWarnings("unused") 17 | @Extension 18 | public class RunActionFactory extends TransientActionFactory { 19 | @Override 20 | public Class type() { 21 | return Run.class; 22 | } 23 | 24 | @Nonnull 25 | @Override 26 | public Collection createFor(@Nonnull Run target) { 27 | Job job = target.getParent(); 28 | LogEventHelper.UrlQueryBuilder builder=new LogEventHelper.UrlQueryBuilder() 29 | .putIfAbsent("host", SplunkJenkinsInstallation.get().getMetadataHost()) 30 | .putIfAbsent("job", job.getFullName()) 31 | .putIfAbsent("build", target.getNumber() + ""); 32 | File junitFile = new File(target.getRootDir(), "junitResult.xml"); 33 | if (junitFile.exists() || job.getClass().getName().startsWith("hudson.maven.")) { 34 | String query =builder.build(); 35 | return Collections.singleton(new LinkSplunkAction("test_analysis", query, "Splunk")); 36 | } 37 | String query =builder.putIfAbsent("type","build").build(); 38 | return Collections.singleton(new LinkSplunkAction("build_analysis", query, "Splunk")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/test/java/com/splunk/splunkjenkins/SplunkinsDslVariableTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 4 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 5 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 6 | import org.junit.Before; 7 | import org.junit.ClassRule; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.jvnet.hudson.test.BuildWatcher; 11 | import org.jvnet.hudson.test.JenkinsRule; 12 | 13 | import java.util.UUID; 14 | 15 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 16 | 17 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 18 | import static org.junit.Assert.*; 19 | 20 | public class SplunkinsDslVariableTest { 21 | @ClassRule 22 | public static BuildWatcher buildWatcher = new BuildWatcher(); 23 | @Rule 24 | public JenkinsRule r = new JenkinsRule(); 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | org.junit.Assume.assumeTrue(checkTokenAvailable()); 29 | } 30 | 31 | @Test 32 | public void testDslScript() throws Exception { 33 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 34 | String eventSource = "test_dsl_var_" + UUID.randomUUID().toString(); 35 | p.setDefinition(new CpsFlowDefinition("node { splunkins.send('hello', '" + eventSource + "') }")); 36 | WorkflowRun b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 37 | assertFalse(b1.isBuilding()); 38 | assertTrue(b1.getDuration() > 0); 39 | String query = "index=" + SplunkConfigUtil.INDEX_NAME + " source=" + eventSource; 40 | int expected = 1; 41 | verifySplunkSearchResult(query, b1.getTimeInMillis(), expected); 42 | } 43 | } -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/java/com/splunk/splunkjenkins/SplunkinsDslVariable.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | 4 | import hudson.Extension; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import hudson.util.LogTaskListener; 8 | import org.jenkinsci.plugins.workflow.cps.CpsScript; 9 | import org.jenkinsci.plugins.workflow.cps.GlobalVariable; 10 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 11 | 12 | import javax.annotation.Nonnull; 13 | import java.lang.reflect.Field; 14 | import java.util.Map; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getBuildVariables; 19 | 20 | @Extension(optional = true) 21 | public class SplunkinsDslVariable extends GlobalVariable { 22 | @Nonnull 23 | @Override 24 | public String getName() { 25 | return "splunkins"; 26 | } 27 | 28 | @Nonnull 29 | @Override 30 | public Object getValue(@Nonnull CpsScript script) throws Exception { 31 | Run build = script.$build(); 32 | if (build == null) { 33 | throw new IllegalStateException("cannot find associated build"); 34 | } 35 | // try to access WorkflowRun.listener 36 | TaskListener listener = TaskListener.NULL; 37 | try { 38 | Field field = WorkflowRun.class.getDeclaredField("listener"); 39 | field.setAccessible(true); 40 | listener = (TaskListener) field.get(build); 41 | } catch (Exception e) { 42 | listener = new LogTaskListener(Logger.getLogger(SplunkinsDslVariable.class.getName()), Level.INFO); 43 | } 44 | Map buildParameters = getBuildVariables(build); 45 | RunDelegate delegate = new RunDelegate(build, buildParameters, listener); 46 | return delegate; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/LoggingInitStep.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.splunk.splunkjenkins.utils.LogEventHelper; 4 | import hudson.init.Initializer; 5 | import jenkins.util.Timer; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.logging.Handler; 9 | import java.util.logging.Level; 10 | import java.util.logging.Logger; 11 | 12 | import static hudson.init.InitMilestone.JOB_LOADED; 13 | 14 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE") 15 | public class LoggingInitStep { 16 | private final static String rootLoggerName = ""; 17 | 18 | @Initializer(after = JOB_LOADED) 19 | public static void setupSplunkJenkins() { 20 | Timer.get().schedule(new Runnable() { 21 | @Override 22 | public void run() { 23 | registerHandler(); 24 | } 25 | }, 3, TimeUnit.MINUTES); 26 | } 27 | 28 | protected static void registerHandler() { 29 | Handler[] handlers = Logger.getLogger(rootLoggerName).getHandlers(); 30 | for (Handler handler : handlers) { 31 | if (handler instanceof JdkSplunkLogHandler) { 32 | // already registered 33 | return; 34 | } 35 | } 36 | //only log warning message for HealthMonitor which runs every 20s 37 | Logger.getLogger(HealthMonitor.class.getName()).setLevel(Level.WARNING); 38 | Logger.getLogger(rootLoggerName).addHandler(JdkSplunkLogHandler.LogHolder.LOG_HANDLER); 39 | //init plugin 40 | SplunkJenkinsInstallation.get().updateCache(); 41 | SplunkJenkinsInstallation.markComplete(true); 42 | Logger.getLogger(LoggingInitStep.class.getName()).info("plugin splunk-devops version " + LogEventHelper.getBuildVersion() + " loaded"); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/help-groovyBinding.html: -------------------------------------------------------------------------------- 1 |
2 |

Provide a groovy script to customize event process, 3 | will be executed when job is completed

4 | 5 |
6 |
7 | You can customize the events sent to splunk by call: 8 |
  
 9 | //send job metadata and junit reports with page size set to 50 (each event contains max 50 test cases)
10 | splunkins.sendTestReport(50)
11 | //send coverage, each event contains max 50 class metrics
12 | splunkins.sendCoverageReport(50)
13 | //send all logs from workspace to splunk, with each file size limits to 10MB
14 | splunkins.archive("**/*.log", null, false, "10MB")
15 | 
16 | 
17 | The groovy script can use the variable splunkins, which provides access to the following objects and methods: 18 |
 
19 | 
20 | Action getAction(Class type);
21 | Action getActionByClassName(String className);
22 | //send message to splunk
23 | boolean send(Object message);
24 | //Archive all configured artifacts from slave, with each file size limit to 10MB, using ant patterns defined in http://ant.apache.org/manual/Types/fileset.html
25 | archive(String includes, String excludes = null, boolean uploadFromSlave = false, String fileSizeLimit = "")
26 | //will send build parameters as metadata and with the object returned from closure to splunk
27 | sendReport(Closure closure)
28 | //a junit report with summary of passes,failures,skips and details of testcase
29 | getJunitReport()
30 | //a a list of junit report each with summary of passes,failures,skips and details of testcase
31 | //each report contains max pageSize testcases
32 | getJunitReport(int pageSize)
33 | sendTestReport(pageSize)  //send Test report, with pagination support
34 | sendCoverageReport(pageSize)  //send coverage report, with pagination support
35 |   
36 |
37 |
38 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/JaCoCo/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | true 9 | false 10 | false 11 | false 12 | 13 | false 14 | 15 | 16 | **/**.exec 17 | **/classes 18 | **/java 19 | 20 | 21 | 0 22 | 0 23 | 0 24 | 0 25 | 0 26 | 0 27 | 0 28 | 0 29 | 0 30 | 0 31 | 0 32 | 0 33 | false 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/test/java/com/splunk/splunkjenkins/SplunkLogFileStepTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 4 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 5 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 6 | import org.junit.Before; 7 | import org.junit.ClassRule; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.jvnet.hudson.test.BuildWatcher; 11 | import org.jvnet.hudson.test.JenkinsRule; 12 | 13 | import java.util.UUID; 14 | 15 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 16 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 17 | import static org.junit.Assert.*; 18 | 19 | public class SplunkLogFileStepTest { 20 | @ClassRule 21 | public static BuildWatcher buildWatcher = new BuildWatcher(); 22 | @Rule 23 | public JenkinsRule r = new JenkinsRule(); 24 | String fileName = UUID.randomUUID().toString() + ".log"; 25 | 26 | private String jobScript = "node{\n" + 27 | "sh \"echo testjob\";\n" + 28 | "sh \"echo 'hello world' > " + fileName + "\";\n" + 29 | "sendSplunkFile includes: \"*.log\";\n" + 30 | "}"; 31 | 32 | @Before 33 | public void setUp() throws Exception { 34 | org.junit.Assume.assumeTrue(checkTokenAvailable()); 35 | } 36 | 37 | @Test 38 | public void testSendFile() throws Exception { 39 | long startTime = System.currentTimeMillis(); 40 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 41 | p.setDefinition(new CpsFlowDefinition(jobScript)); 42 | WorkflowRun b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 43 | assertFalse(b1.isBuilding()); 44 | r.assertLogContains("testjob", b1); 45 | assertTrue(b1.getDuration() > 0); 46 | //check log 47 | verifySplunkSearchResult("source=" + b1.getUrl() + fileName, startTime, 1); 48 | } 49 | } -------------------------------------------------------------------------------- /splunk-devops-extend/src/test/java/com/splunk/splunkjenkins/SplunkConsoleLogStepTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 4 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 5 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 6 | import org.junit.Before; 7 | import org.junit.ClassRule; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.jvnet.hudson.test.BuildWatcher; 11 | import org.jvnet.hudson.test.JenkinsRule; 12 | 13 | import java.util.UUID; 14 | 15 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 16 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 17 | import static org.junit.Assert.assertFalse; 18 | import static org.junit.Assert.assertTrue; 19 | 20 | public class SplunkConsoleLogStepTest { 21 | @ClassRule 22 | public static BuildWatcher buildWatcher = new BuildWatcher(); 23 | @Rule 24 | public JenkinsRule r = new JenkinsRule(); 25 | String id = UUID.randomUUID().toString(); 26 | 27 | private String jobScript = "sendSplunkConsoleLog {" + 28 | "node{\n" + 29 | " sh \"echo testjob\";\n" + 30 | " sh \"echo " + id + "\";\n" + 31 | " }" + 32 | "}"; 33 | 34 | @Before 35 | public void setUp() throws Exception { 36 | org.junit.Assume.assumeTrue(checkTokenAvailable()); 37 | } 38 | 39 | @Test 40 | public void testSendFile() throws Exception { 41 | long startTime = System.currentTimeMillis(); 42 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 43 | p.setDefinition(new CpsFlowDefinition(jobScript)); 44 | WorkflowRun b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 45 | assertFalse(b1.isBuilding()); 46 | r.assertLogContains("testjob", b1); 47 | assertTrue(b1.getDuration() > 0); 48 | //check log 49 | verifySplunkSearchResult("source=" + b1.getUrl() + "console " + id, startTime, 1); 50 | } 51 | } -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/Clover/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | false 9 | 10 | 11 | false 12 | false 13 | 14 | 15 | 0 16 | 0 17 | 18 | false 19 | project 20 | 21 | 22 | 23 | true 24 | false 25 | false 26 | false 27 | 28 | false 29 | 30 | 31 | 32 | 33 | clover.xml 34 | 35 | 70 36 | 80 37 | 80 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/test/java/com/splunk/splunkjenkins/PipelineExecuteDiagramTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 4 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 5 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 6 | import org.junit.Before; 7 | import org.junit.ClassRule; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.jvnet.hudson.test.BuildWatcher; 11 | import org.jvnet.hudson.test.JenkinsRule; 12 | 13 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 14 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 15 | import static org.junit.Assert.assertFalse; 16 | import static org.junit.Assert.assertTrue; 17 | 18 | public class PipelineExecuteDiagramTest { 19 | @ClassRule 20 | public static BuildWatcher buildWatcher = new BuildWatcher(); 21 | @Rule 22 | public JenkinsRule r = new JenkinsRule(); 23 | private String jobScript = "properties([splunkinsJobOption(enableDiagram: true)])\n" + 24 | "stage(\"unit-test\"){\n" + 25 | " node{\n" + 26 | " echo \"hello\"\n" + 27 | " echo \"hello world2\"\n" + 28 | " }\n" + 29 | "}"; 30 | 31 | @Before 32 | public void setUp() throws Exception { 33 | org.junit.Assume.assumeTrue(checkTokenAvailable()); 34 | } 35 | 36 | @Test 37 | public void testExecuteDiagram() throws Exception { 38 | long startTime = System.currentTimeMillis(); 39 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "testExecuteDiagram"); 40 | p.setDefinition(new CpsFlowDefinition(jobScript)); 41 | WorkflowRun b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 42 | assertFalse(b1.isBuilding()); 43 | r.assertLogContains("hello", b1); 44 | assertTrue(b1.getDuration() > 0); 45 | //check exec_node 46 | verifySplunkSearchResult("source=" + b1.getUrl() + "graphviz", startTime, 1); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/JunitTestCaseGroup.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import hudson.Util; 5 | import hudson.tasks.test.TestResult; 6 | 7 | import java.io.Serializable; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @SuppressFBWarnings("URF_UNREAD_FIELD") 12 | public class JunitTestCaseGroup implements Serializable{ 13 | int failures; 14 | int passes; 15 | int skips; 16 | int total; 17 | float duration; 18 | //alias, fields for json serialization 19 | int tests; 20 | float time; 21 | //backward compatible with junit3 xml which has errors field 22 | int errors = 0; 23 | List testcase = new ArrayList<>(); 24 | 25 | public void add(TestResult result) { 26 | this.failures += result.getFailCount(); 27 | this.passes += result.getPassCount(); 28 | this.skips += result.getSkipCount(); 29 | this.total += result.getTotalCount(); 30 | this.duration += result.getDuration(); 31 | //update alias 32 | this.tests = this.total; 33 | this.time = this.duration; 34 | this.testcase.add(result); 35 | } 36 | 37 | public int getFailures() { 38 | return failures; 39 | } 40 | 41 | public int getPasses() { 42 | return passes; 43 | } 44 | 45 | public int getSkips() { 46 | return skips; 47 | } 48 | 49 | public int getTotal() { 50 | return total; 51 | } 52 | 53 | public float getDuration() { 54 | return duration; 55 | } 56 | 57 | public List getTestcase() { 58 | return testcase; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "failures: " + failures + 64 | ", passes: " + passes + 65 | ", skips: " + skips + 66 | ", errors: " + errors + 67 | ", total: " + total + 68 | ", duration: " + Util.getTimeSpanString(1000L * (long) duration); 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/model/MetaDataConfigItem/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 18 | 21 | 22 | 23 | 24 | 28 | 29 | 30 |
31 | 32 |
33 |
34 |
13 | 14 | 16 | 17 | 19 | 20 |
25 | 26 | 27 |
35 | 36 | 59 | 60 |
-------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/listeners/LoggingComputerListener.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.listeners; 2 | 3 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 4 | import com.splunk.splunkjenkins.utils.SplunkLogService; 5 | import hudson.Extension; 6 | import hudson.model.Computer; 7 | import hudson.model.TaskListener; 8 | import hudson.slaves.ComputerListener; 9 | import hudson.slaves.OfflineCause; 10 | 11 | import javax.annotation.CheckForNull; 12 | import javax.annotation.Nonnull; 13 | import java.io.IOException; 14 | import java.util.Map; 15 | 16 | import static com.splunk.splunkjenkins.Constants.EVENT_CAUSED_BY; 17 | import static com.splunk.splunkjenkins.model.EventType.SLAVE_INFO; 18 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getComputerStatus; 19 | 20 | @SuppressWarnings("unused") 21 | @Extension 22 | public class LoggingComputerListener extends ComputerListener { 23 | @Override 24 | public void onOnline(Computer c, TaskListener listener) throws IOException, InterruptedException { 25 | updateStatus(c, "Online"); 26 | listener.getLogger().flush(); 27 | } 28 | 29 | @Override 30 | public void onOffline(@Nonnull Computer c, @CheckForNull OfflineCause cause) { 31 | updateStatus(c, "Offline"); 32 | } 33 | 34 | @Override 35 | public void onTemporarilyOnline(Computer c) { 36 | updateStatus(c, "Temporarily Online"); 37 | } 38 | 39 | @Override 40 | public void onTemporarilyOffline(Computer c, OfflineCause cause) { 41 | updateStatus(c, "Temporarily Offline"); 42 | } 43 | 44 | @Override 45 | public void onLaunchFailure(Computer c, TaskListener taskListener) throws IOException, InterruptedException { 46 | updateStatus(c, "Launch Failure"); 47 | taskListener.getLogger().flush(); 48 | } 49 | 50 | private void updateStatus(Computer c, String eventSource) { 51 | if (SplunkJenkinsInstallation.get().isEventDisabled(SLAVE_INFO)) { 52 | return; 53 | } 54 | Map slaveInfo = getComputerStatus(c); 55 | slaveInfo.put(EVENT_CAUSED_BY, eventSource); 56 | SplunkLogService.getInstance().send(slaveInfo, SLAVE_INFO); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/listeners/LoggingItemListener.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.listeners; 2 | 3 | import com.splunk.splunkjenkins.utils.SplunkLogService; 4 | import hudson.Extension; 5 | import hudson.model.Item; 6 | import hudson.model.listeners.ItemListener; 7 | 8 | import java.io.File; 9 | 10 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getRelativeJenkinsHomePath; 11 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getUserName; 12 | import static com.splunk.splunkjenkins.utils.LogEventHelper.logUserAction; 13 | 14 | @Extension 15 | public class LoggingItemListener extends ItemListener { 16 | @Override 17 | public void onCreated(Item item) { 18 | logUserAction(getUserName(), Messages.audit_create_item(getConfigPath(item))); 19 | } 20 | 21 | @Override 22 | public void onCopied(Item src, Item item) { 23 | logUserAction(getUserName(), Messages.audit_cloned_item(getConfigPath(item), getConfigPath(src))); 24 | } 25 | 26 | @Override 27 | public void onDeleted(Item item) { 28 | logUserAction(getUserName(), Messages.audit_delete_item(getConfigPath(item))); 29 | } 30 | 31 | @Override 32 | public void onRenamed(Item item, String oldName, String newName) { 33 | //no-op, we use onLocationChanged 34 | } 35 | 36 | @Override 37 | public void onUpdated(Item item) { 38 | //prior to delete, makeDisabled was called and onUpdated is triggered 39 | logUserAction(getUserName(), Messages.audit_update_item(getConfigPath(item))); 40 | } 41 | 42 | @Override 43 | public void onLocationChanged(Item item, String oldFullName, String newFullName) { 44 | logUserAction(getUserName(), Messages.audit_rename_item(oldFullName, newFullName)); 45 | } 46 | 47 | private String getConfigPath(Item item) { 48 | if (item == null) { 49 | return "unknown"; 50 | } 51 | return getRelativeJenkinsHomePath(item.getRootDir() + File.separator + "config.xml"); 52 | } 53 | 54 | @Override 55 | public void onBeforeShutdown() { 56 | SplunkLogService.getInstance().stopWorker(); 57 | SplunkLogService.getInstance().releaseConnection(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/utils/LogEventHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | import com.splunk.splunkjenkins.BaseTest; 4 | import hudson.model.Label; 5 | import hudson.model.Slave; 6 | import org.junit.*; 7 | import org.jvnet.hudson.test.JenkinsRule; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.logging.Level; 13 | 14 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 15 | import static org.junit.Assert.*; 16 | 17 | public class LogEventHelperTest extends BaseTest { 18 | private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(LogEventHelper.class.getName()); 19 | 20 | @Test 21 | public void parseFileSize() throws Exception { 22 | long oneMB = 1024 * 1024; 23 | long twoKB = 2 * 1024; 24 | assertEquals(oneMB, LogEventHelper.parseFileSize("1MB")); 25 | assertEquals(512 * 1024, LogEventHelper.parseFileSize("0.5MB")); 26 | assertEquals(twoKB, LogEventHelper.parseFileSize("2KB")); 27 | assertEquals(123535, LogEventHelper.parseFileSize("123535")); 28 | assertEquals(0, LogEventHelper.parseFileSize("12s")); 29 | } 30 | 31 | @Test 32 | public void testSlaveStats() throws Exception { 33 | Slave slave = j.createOnlineSlave(); 34 | Map> slaveStats = LogEventHelper.getSlaveStats(); 35 | assertTrue("should not be empty", !slaveStats.isEmpty()); 36 | String slaveName = slave.getNodeName(); 37 | String monitorName = "ClockMonitor"; 38 | long timeToWait = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(1); 39 | boolean hasMonitorData = false; 40 | while (System.currentTimeMillis() < timeToWait) { 41 | slaveStats = LogEventHelper.getSlaveStats(); 42 | LOG.log(Level.FINER, slaveStats.toString()); 43 | if (slaveStats.containsKey(slaveName)) { 44 | hasMonitorData = slaveStats.get(slaveName).containsKey(monitorName); 45 | 46 | } 47 | if (hasMonitorData) { 48 | break; 49 | } 50 | } 51 | assertTrue(hasMonitorData); 52 | } 53 | } -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/JunitResultAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.Extension; 4 | import hudson.tasks.junit.CaseResult; 5 | import hudson.tasks.junit.SuiteResult; 6 | import hudson.tasks.junit.TestResultAction; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Extension(optional = true) 12 | public class JunitResultAdapter extends AbstractTestResultAdapter { 13 | @Override 14 | public List getTestResult(TestResultAction resultAction) { 15 | List caseResults = new ArrayList<>(); 16 | hudson.tasks.junit.TestResult result = resultAction.getResult(); 17 | for (SuiteResult suite : result.getSuites()) { 18 | for (CaseResult testCase : suite.getCases()) { 19 | caseResults.add(convert(testCase, suite.getName())); 20 | } 21 | } 22 | return caseResults; 23 | } 24 | 25 | /** 26 | * @param methodResult 27 | * @return unified test case result 28 | */ 29 | private TestCaseResult convert(CaseResult methodResult, String suiteName) { 30 | TestCaseResult testCaseResult = new TestCaseResult(); 31 | testCaseResult.setTestName(methodResult.getName()); 32 | testCaseResult.setUniqueName(methodResult.getFullName()); 33 | testCaseResult.setDuration(methodResult.getDuration()); 34 | testCaseResult.setClassName(methodResult.getClassName()); 35 | testCaseResult.setErrorDetails(methodResult.getErrorDetails()); 36 | testCaseResult.setErrorStackTrace(methodResult.getErrorStackTrace()); 37 | testCaseResult.setSkippedMessage(methodResult.getSkippedMessage()); 38 | testCaseResult.setFailedSince(methodResult.getFailedSince()); 39 | testCaseResult.setStderr(methodResult.getStderr()); 40 | testCaseResult.setStdout(methodResult.getStdout()); 41 | testCaseResult.setGroupName(suiteName); 42 | TestStatus status = TestStatus.SKIPPED; 43 | if (!methodResult.isSkipped()) { 44 | status = methodResult.isPassed() ? TestStatus.PASSED : TestStatus.FAILURE; 45 | } 46 | testCaseResult.setStatus(status); 47 | return testCaseResult; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/TeeConsoleLogFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.splunk.splunkjenkins.utils.SplunkLogService; 4 | import hudson.model.FreeStyleBuild; 5 | import hudson.model.FreeStyleProject; 6 | import hudson.tasks.Shell; 7 | 8 | import java.util.UUID; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.logging.Logger; 11 | 12 | import org.junit.After; 13 | import org.junit.Before; 14 | import org.junit.Rule; 15 | import org.junit.Test; 16 | import org.jvnet.hudson.test.CaptureEnvironmentBuilder; 17 | import org.jvnet.hudson.test.JenkinsRule; 18 | 19 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 20 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertFalse; 23 | import static org.junit.Assert.fail; 24 | 25 | public class TeeConsoleLogFilterTest extends BaseTest { 26 | private static final Logger LOG = Logger.getLogger(TeeConsoleLogFilterTest.class.getName()); 27 | 28 | @Test 29 | public void decorateLogger() throws Exception { 30 | FreeStyleProject p = j.createFreeStyleProject("console_" + UUID.randomUUID()); 31 | CaptureEnvironmentBuilder captureEnvironment = new CaptureEnvironmentBuilder(); 32 | p.getBuildersList().add(captureEnvironment); 33 | p.getBuildersList().add(new Shell("echo $PATH;echo $$")); 34 | long eventCount = SplunkLogService.getInstance().getSentCount(); 35 | FreeStyleBuild b = j.buildAndAssertSuccess(p); 36 | long timeToWait = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(2); 37 | while (eventCount >= SplunkLogService.getInstance().getSentCount() && (p.getLastBuild() == null || p.getLastBuild().isBuilding())) { 38 | Thread.sleep(1000); 39 | if (System.currentTimeMillis() > timeToWait) { 40 | LOG.fine("queue size:" + SplunkLogService.getInstance().getQueueSize()); 41 | fail("can not send event in time"); 42 | } 43 | } 44 | String query = "index=" + SplunkConfigUtil.INDEX_NAME + " source=" + b.getUrl() + "console"; 45 | int expected = 5; 46 | verifySplunkSearchResult(query, b.getTimeInMillis(), expected); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/utils/TestCaseResultUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.utils; 2 | 3 | import com.splunk.splunkjenkins.model.JunitResultAdapter; 4 | import com.splunk.splunkjenkins.model.JunitTestCaseGroup; 5 | import hudson.model.Run; 6 | import hudson.tasks.junit.TestResult; 7 | import hudson.tasks.junit.TestResultAction; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.io.FileWriter; 12 | import java.util.List; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | public class TestCaseResultUtilsTest { 17 | public void splitJunitTestCase(int total, int pageSize) throws Exception { 18 | TestResult result = new TestResult(); 19 | File junitFile = File.createTempFile("junit", ".xml"); 20 | FileWriter out = new FileWriter(junitFile); 21 | out.write("\n"); 22 | out.write("\n" + 23 | "\t\n" + 24 | "\t\n" + 25 | ""); 26 | for (int i = 1; i < total; i++) { 27 | out.write("") 29 | .concat("\n")); 30 | } 31 | out.write(""); 32 | out.close(); 33 | result.parse(junitFile); 34 | result.tally(); 35 | assertEquals(total, result.getTotalCount()); 36 | assertEquals(1, result.getFailCount()); 37 | 38 | TestResultAction action = new TestResultAction((Run) null, result, null); 39 | JunitResultAdapter adapter = new JunitResultAdapter(); 40 | List suites = TestCaseResultUtils.split(adapter.getTestResult(action) 41 | , pageSize); 42 | int remained = (total % pageSize == 0) ? 0 : 1; 43 | int pageCount = total / pageSize + remained; 44 | assertEquals(pageCount, suites.size()); 45 | } 46 | 47 | @Test 48 | public void testSplitReminder() throws Exception { 49 | splitJunitTestCase(512, 5); 50 | } 51 | 52 | @Test 53 | public void testSplitDivide() throws Exception { 54 | splitJunitTestCase(5, 5); 55 | } 56 | } -------------------------------------------------------------------------------- /splunk-devops-extend/src/test/java/com/splunk/splunkjenkins/StageStepNodesTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import hudson.model.labels.LabelAtom; 4 | import hudson.slaves.DumbSlave; 5 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 6 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 7 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 8 | import org.junit.Before; 9 | import org.junit.ClassRule; 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.jvnet.hudson.test.BuildWatcher; 13 | import org.jvnet.hudson.test.JenkinsRule; 14 | 15 | import static com.splunk.splunkjenkins.SplunkConfigUtil.checkTokenAvailable; 16 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 17 | import static org.junit.Assert.assertFalse; 18 | import static org.junit.Assert.assertTrue; 19 | 20 | public class StageStepNodesTest { 21 | @ClassRule 22 | public static BuildWatcher buildWatcher = new BuildWatcher(); 23 | @Rule 24 | public JenkinsRule r = new JenkinsRule(); 25 | private String jobScript = "stage(\"unit-test\"){\n" + 26 | " node(\"ci-1\"){\n" + 27 | " echo \"hello\"\n" + 28 | " echo \"hello world2\"\n" + 29 | " }\n" + 30 | " node(\"ci-2\"){\n" + 31 | " echo \"hello\"\n" + 32 | " }\n" + 33 | "}"; 34 | 35 | @Before 36 | public void setUp() throws Exception { 37 | org.junit.Assume.assumeTrue(checkTokenAvailable()); 38 | } 39 | 40 | @Test 41 | public void testStageNodes() throws Exception { 42 | long startTime = System.currentTimeMillis(); 43 | DumbSlave node = r.createOnlineSlave(new LabelAtom("ci-1")); 44 | DumbSlave node1 = r.createOnlineSlave(new LabelAtom("ci-2")); 45 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 46 | p.setDefinition(new CpsFlowDefinition(jobScript)); 47 | WorkflowRun b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 48 | assertFalse(b1.isBuilding()); 49 | r.assertLogContains("hello", b1); 50 | assertTrue(b1.getDuration() > 0); 51 | //check exec_node 52 | verifySplunkSearchResult("\"stages{}.children{}.exec_node\"=\"" + node.getNodeName() + "\"", startTime, 1); 53 | verifySplunkSearchResult("\"stages{}.children{}.exec_node\"=\"" + node1.getNodeName() + "\"", startTime, 1); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/CoverageMetricTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import hudson.model.AbstractBuild; 4 | import hudson.model.FreeStyleProject; 5 | import org.junit.Test; 6 | import org.jvnet.hudson.test.recipes.LocalData; 7 | 8 | import java.util.UUID; 9 | 10 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 11 | 12 | public class CoverageMetricTest extends BaseTest { 13 | @LocalData 14 | @Test 15 | public void getCoberturaReport() throws Exception { 16 | String jobName = "Cobertura"; 17 | getCoverageReport(jobName, 50); 18 | } 19 | 20 | @LocalData 21 | @Test 22 | public void getCloverReport() throws Exception { 23 | String jobName = "Clover"; 24 | getCoverageReport(jobName, 50); 25 | } 26 | 27 | @LocalData 28 | @Test 29 | public void getJaCoCoReport() throws Exception { 30 | String jobName = "JaCoCo"; 31 | getCoverageReport(jobName, 50); 32 | } 33 | 34 | public void getCoverageReport(String jobName, int methodPercentage) throws Exception { 35 | FreeStyleProject project = (FreeStyleProject) j.getInstance().getItem(jobName); 36 | String newName = UUID.randomUUID().toString(); 37 | project.renameTo(newName); 38 | long startTime = System.currentTimeMillis(); 39 | AbstractBuild build = project.scheduleBuild2(0).get(); 40 | //verify coverage summary 41 | String query = "event_tag=job_event build_url=" + build.getUrl() + " \"coverage.methods\" >= " + methodPercentage; 42 | verifySplunkSearchResult(query, startTime, 1); 43 | //verify details 44 | query = "source=\"unit_test/coverage\" build_url=" + build.getUrl() + "|" 45 | + "rename \"coverage{}.methods_percentage\" as methods |mvexpand methods " + 46 | "|search methods>=" + methodPercentage; 47 | verifySplunkSearchResult(query, startTime, 1); 48 | //check total and covered number 49 | query = "splunk_server=local index=plugin_sandbox build_url=" + build.getUrl() + 50 | " source=\"unit_test/coverage\" \"com.mycompany\"\n" + 51 | "|spath output=coverage_json path=coverage{}|mvexpand coverage_json\n" + 52 | "|spath input=coverage_json|where name=\"com.mycompany\" and methods_total>methods_covered|table methods*"; 53 | verifySplunkSearchResult(query, startTime, 1); 54 | } 55 | } -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/Messages.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | #see also http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html 21 | DisplayName=Splunk-Jenkins 22 | Description=A Splunk-Jenkins plugin for Splunking Jenkins. 23 | PleaseProvideHost=Please provide the hostname to a Splunk instance. 24 | CloudHostPrefix=You are using Splunk Cloud, please provide host name starts input- or http-inputs-, \ 25 | please try input-{0} or http-inputs-{0}. See also http://dev.splunk.com/view/event-collector/SP-CAAAE7G 26 | HostNameSchemaWarning=Invalid hostname, do you mean {0}? 27 | HostNameListWarning=Multiple hosts is not supported, please setup load balancer, and user the virtual name 28 | HostNameInvalid=Failed to validate hostname 29 | ValueIntErrorMsg=This value must be a valid int. 30 | ValueCannotBeBlank=This value cannot be blank. 31 | ConfigBuildStepTitle=Send data to Splunk 32 | ConfigBuildStepSendLog=Send build log 33 | ConfigBuildStepSendEnvVars=Send environment variables 34 | ConfigBuildStepSendFiles=Files to send as an event 35 | ConfigBuildFileToAppend=File to append to event 36 | InvalidToken=Token is invalid 37 | InvalidPattern=The pattern is invalid, please check Pattern 38 | InvalidHostOrToken=Invalid config, please check Hostname or Token 39 | SplunArtifactArchive=Send files to Splunk 40 | SplunkIconName=/plugin/splunk-devops/images/splunk_logo_green.png 41 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/AbstractTestResultAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.ExtensionList; 4 | import hudson.ExtensionPoint; 5 | import hudson.model.Run; 6 | import hudson.tasks.test.AbstractTestResultAction; 7 | import hudson.tasks.test.TestResult; 8 | import org.jvnet.tiger_types.Types; 9 | 10 | import javax.annotation.Nonnull; 11 | import java.lang.reflect.ParameterizedType; 12 | import java.lang.reflect.Type; 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.List; 16 | 17 | public abstract class AbstractTestResultAdapter implements ExtensionPoint { 18 | public final Class targetType; 19 | 20 | public AbstractTestResultAdapter() { 21 | Type type = Types.getBaseClass(getClass(), AbstractTestResultAdapter.class); 22 | if (type instanceof ParameterizedType) 23 | targetType = Types.erasure(Types.getTypeArgument(type, 0)); 24 | else 25 | throw new IllegalStateException(getClass() + " uses the raw type for extending AbstractTestResultAdapter"); 26 | 27 | } 28 | 29 | public A getAction(Run run) { 30 | return run.getAction(targetType); 31 | } 32 | 33 | public boolean isApplicable(Run build) { 34 | return getAction(build) != null; 35 | } 36 | 37 | /** 38 | * @param build jenkins build 39 | * @return all the test result added in the build 40 | */ 41 | @Nonnull 42 | public static List getTestResult(Run build) { 43 | return getTestResult(build, Collections.emptyList()); 44 | } 45 | 46 | /** 47 | * @param build jenkins build 48 | * @param ignoredActions a list of test action class name 49 | * @return the test result filtered by the test action name 50 | */ 51 | @Nonnull 52 | public static List getTestResult(Run build, @Nonnull List ignoredActions) { 53 | List adapters = ExtensionList.lookup(AbstractTestResultAdapter.class); 54 | List testResults = new ArrayList<>(); 55 | for (AbstractTestResultAdapter adapter : adapters) { 56 | if (adapter.isApplicable(build)) { 57 | AbstractTestResultAction action = adapter.getAction(build); 58 | if (ignoredActions.contains(action.getClass().getName())) { 59 | // the test action is ignored 60 | continue; 61 | } 62 | testResults.addAll(adapter.getTestResult(action)); 63 | } 64 | } 65 | return testResults; 66 | } 67 | 68 | public abstract List getTestResult(A resultAction); 69 | } 70 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/TestResultAdapterTest/jobs/xunit_job1/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | true 9 | false 10 | false 11 | false 12 | 13 | false 14 | 15 | 16 | cat >test-result.xml <<'EOF' 17 | <?xml version="1.0" encoding="UTF-8"?> 18 | <testsuite name="hudson.util.ProcessTreeTest" time="0.357" tests="3" errors="0" skipped="0" failures="0"> 19 | <testcase name="remoting" classname="hudson.util.ProcessTreeTest" time="0.157"/> 20 | <testcase name="remoting-a" classname="hudson.util.ProcessTreeTest" time="0.157"/> 21 | <testcase name="remoting-b" classname="hudson.util.ProcessTreeTest" time="0.157"/> 22 | 23 | </testsuite> 24 | EOF 25 | 26 | 27 | 28 | 29 | 30 | 31 | test-result.xml 32 | true 33 | true 34 | true 35 | true 36 | 37 | 38 | 39 | 40 | 41 | 1 42 | 43 | 2 44 | 45 | 46 | 47 | 1 48 | 49 | 2 50 | 51 | 52 | 1 53 | 54 | 3000 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/SplunkArchiveFileTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import hudson.model.FreeStyleBuild; 4 | import hudson.model.FreeStyleProject; 5 | import hudson.model.Label; 6 | import hudson.tasks.Shell; 7 | import org.junit.Test; 8 | import org.jvnet.hudson.test.CaptureEnvironmentBuilder; 9 | 10 | import java.util.UUID; 11 | import java.util.logging.Logger; 12 | 13 | import static com.splunk.splunkjenkins.SplunkConfigUtil.INDEX_NAME; 14 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 15 | import static org.junit.Assert.assertNotNull; 16 | import static org.junit.Assert.fail; 17 | 18 | public class SplunkArchiveFileTest extends BaseTest { 19 | public static Object result = null; 20 | private static final Logger logger = Logger.getLogger(SplunkArchiveFileTest.class.getName()); 21 | 22 | public String buildWithScript(String groovyScript) throws Exception { 23 | Label label = j.jenkins.getLabel("filetest"); 24 | j.createOnlineSlave(label); 25 | FreeStyleProject project = j.createFreeStyleProject("verify_archive" + UUID.randomUUID()); 26 | CaptureEnvironmentBuilder captureEnvironment = new CaptureEnvironmentBuilder(); 27 | project.getBuildersList().add(captureEnvironment); 28 | project.getBuildersList().add(new Shell("ps -ef >process_list.txt")); 29 | project.setAssignedLabel(label); 30 | SplunkJenkinsInstallation.get().setScriptContent(groovyScript); 31 | SplunkJenkinsInstallation.get().updateCache(); 32 | long start_time = System.currentTimeMillis(); 33 | FreeStyleBuild build = j.buildAndAssertSuccess(project); 34 | String buildUrl = build.getUrl(); 35 | int expected = 5; 36 | String query = "search index=" + INDEX_NAME 37 | + " source=\"" + buildUrl + "process_list.txt\""; 38 | logger.info(query); 39 | verifySplunkSearchResult(query, start_time, expected); 40 | return build.getUrl(); 41 | } 42 | 43 | @Test 44 | public void testUploadFromSlave() { 45 | String script = "println \"uploading files\"\n" + 46 | "splunkins.archive(\"*.txt\",\"\",true,\"0\")"; 47 | try { 48 | buildWithScript(script); 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | fail("upload failed"); 52 | } 53 | } 54 | 55 | @Test 56 | public void testUploadFromMaster() throws Exception { 57 | result = null; 58 | String script = "println \"uploading files\"\n" + 59 | "def sentCount=splunkins.archive(\"*.txt\",\"\",false,\"10MB\");" + 60 | "com.splunk.splunkjenkins.SplunkArchiveFileTest.result=sentCount;" + 61 | "println \"send \"+sentCount"; 62 | buildWithScript(script); 63 | assertNotNull("archive file completed", result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/java/com/splunk/splunkjenkins/SplunkConsoleLogStep.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import hudson.Extension; 5 | import hudson.console.ConsoleLogFilter; 6 | import hudson.model.Run; 7 | import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback; 8 | import org.jenkinsci.plugins.workflow.steps.BodyInvoker; 9 | import org.jenkinsci.plugins.workflow.steps.Step; 10 | import org.jenkinsci.plugins.workflow.steps.StepContext; 11 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor; 12 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 13 | import org.kohsuke.stapler.DataBoundConstructor; 14 | 15 | import javax.annotation.Nonnull; 16 | import java.util.Set; 17 | 18 | public class SplunkConsoleLogStep extends Step { 19 | @DataBoundConstructor 20 | public SplunkConsoleLogStep() { 21 | } 22 | 23 | @Override 24 | public StepExecution start(StepContext context) throws Exception { 25 | return new ConsoleLogExecutionImpl(context); 26 | } 27 | 28 | @Extension(optional = true) 29 | public static class DescriptorImpl extends StepDescriptor { 30 | @Override 31 | public Set> getRequiredContext() { 32 | return ImmutableSet.of(Run.class); 33 | } 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | @Override 39 | public String getFunctionName() { 40 | return "sendSplunkConsoleLog"; 41 | } 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | @Nonnull 47 | @Override 48 | public String getDisplayName() { 49 | return "Send console log Splunk"; 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | @Override 56 | public boolean takesImplicitBlockArgument() { 57 | return true; 58 | } 59 | } 60 | 61 | 62 | public static class ConsoleLogExecutionImpl extends StepExecution { 63 | public ConsoleLogExecutionImpl(StepContext context) { 64 | super(context); 65 | } 66 | 67 | /** 68 | * {@inheritDoc} 69 | */ 70 | @Override 71 | public boolean start() throws Exception { 72 | //refer to WithContextStep implementation 73 | StepContext context = getContext(); 74 | Run run = context.get(Run.class); 75 | ConsoleLogFilter filter = BodyInvoker.mergeConsoleLogFilters(context.get(ConsoleLogFilter.class), new TeeConsoleLogFilter(run)); 76 | context.newBodyInvoker().withContext(filter).withCallback(BodyExecutionCallback.wrap(context)).start(); 77 | return false; 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | */ 83 | @Override 84 | public void stop(@Nonnull Throwable cause) throws Exception { 85 | getContext().onFailure(cause); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /splunk-devops/src/main/groovy/com/splunk/splunkjenkins/UserActionDSL.groovy: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins 2 | 3 | import com.splunk.splunkjenkins.listeners.LoggingRunListener 4 | import com.splunk.splunkjenkins.utils.LogEventHelper 5 | import hudson.model.Run 6 | import hudson.model.TaskListener 7 | import hudson.util.spring.ClosureScript 8 | import jenkins.model.Jenkins 9 | import org.apache.commons.lang.StringUtils 10 | import org.codehaus.groovy.control.CompilerConfiguration 11 | import org.codehaus.groovy.control.customizers.ImportCustomizer 12 | import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval 13 | import org.jenkinsci.plugins.scriptsecurity.scripts.languages.GroovyLanguage 14 | 15 | import java.util.logging.Level 16 | import java.util.logging.Logger 17 | 18 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getBuildVariables 19 | 20 | public class UserActionDSL { 21 | static final LOG = Logger.getLogger(LoggingRunListener.class.name) 22 | 23 | public void perform(Run build, TaskListener listener, GroovyCodeSource codeSource) { 24 | try { 25 | Map buildParameters = getBuildVariables(build); 26 | String scriptText=codeSource.getScriptText() 27 | if (StringUtils.isNotEmpty(scriptText)) { 28 | def workSpace; 29 | if (build.metaClass.respondsTo(build, "getWorkspace")) { 30 | //getWorkspace defined in build 31 | workSpace = build.workspace; 32 | } 33 | RunDelegate delegate = new RunDelegate(build: build, workSpace: workSpace, 34 | env: buildParameters, listener: listener); 35 | Binding binding = new Binding(); 36 | binding.setVariable("splunkins", delegate); 37 | try { 38 | //check approval, will throw UnapprovedUsageException 39 | ScriptApproval.get().using(scriptText, GroovyLanguage.get()) 40 | //call setDelegate to RunDelegate instance and run 41 | CompilerConfiguration cc = new CompilerConfiguration(); 42 | cc.scriptBaseClass = ClosureScript.class.name; 43 | ImportCustomizer ic = new ImportCustomizer() 44 | ic.addStaticStars(LogEventHelper.class.name) 45 | ic.addStarImport("jenkins.model") 46 | cc.addCompilationCustomizers(ic) 47 | ClosureScript dslScript = (ClosureScript) new GroovyShell(Jenkins.instance.pluginManager.uberClassLoader, binding, cc) 48 | .parse(codeSource) 49 | dslScript.setDelegate(delegate); 50 | dslScript.run() 51 | } catch (Exception e) { 52 | LOG.log(Level.SEVERE, "UserActionDSL script failed", e); 53 | e.printStackTrace(listener.getLogger()) 54 | } 55 | listener.getLogger().flush(); 56 | } 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | } 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/java/com/splunk/splunkjenkins/PipelineGraphVizSupport.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.splunk.splunkjenkins.model.EventType; 4 | import com.splunk.splunkjenkins.model.LoggingJobExtractor; 5 | import com.splunk.splunkjenkins.utils.SplunkLogService; 6 | import hudson.Extension; 7 | import org.jenkinsci.plugins.workflow.graph.BlockEndNode; 8 | import org.jenkinsci.plugins.workflow.graph.BlockStartNode; 9 | import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker; 10 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 11 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 12 | 13 | import java.util.Collections; 14 | import java.util.Map; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | /** 19 | * The getDot code is borrowed from https://plugins.jenkins.io/workflow-job 20 | */ 21 | @Extension 22 | public class PipelineGraphVizSupport extends LoggingJobExtractor { 23 | private static final String SUFFIX = "graphviz"; 24 | private static final Logger LOGGER = Logger.getLogger(PipelineGraphVizSupport.class.getName()); 25 | 26 | @Override 27 | public Map extract(WorkflowRun workflowRun, boolean completed) { 28 | if (!completed) { 29 | return Collections.EMPTY_MAP; 30 | } 31 | if (!SplunkJenkinsInstallation.get().isJobIgnored(workflowRun.getUrl())) { 32 | SplunkPipelineJobProperty jobProperty = workflowRun.getParent().getProperty(SplunkPipelineJobProperty.class); 33 | LOGGER.log(Level.FINE, "job {0}, property {1}", new Object[]{workflowRun.getUrl(), jobProperty}); 34 | if (jobProperty != null && jobProperty.isDiagramEnabled()) { 35 | String dotStr = getDot(workflowRun); 36 | String source = workflowRun.getUrl() + SUFFIX; 37 | SplunkLogService.getInstance().send(dotStr, EventType.BUILD_EVENT, source); 38 | } 39 | } 40 | return Collections.EMPTY_MAP; 41 | } 42 | 43 | 44 | private String getDot(WorkflowRun run) { 45 | StringBuffer buffer = new StringBuffer(); 46 | buffer.append("digraph G {\n"); 47 | FlowGraphWalker walker = new FlowGraphWalker(run.getExecution()); 48 | for (FlowNode n : walker) { 49 | for (FlowNode p : n.getParents()) { 50 | buffer.append(String.format("%s -> %s%n", p.getId(), n.getId())); 51 | } 52 | 53 | if (n instanceof BlockStartNode) { 54 | buffer.append(String.format("%s [shape=trapezium]%n", n.getId())); 55 | } else if (n instanceof BlockEndNode) { 56 | BlockEndNode sn = (BlockEndNode) n; 57 | buffer.append(String.format("%s [shape=invtrapezium]%n", n.getId())); 58 | buffer.append(String.format("%s -> %s [style=dotted]%n", sn.getStartNode().getId(), n.getId())); 59 | } 60 | buffer.append(String.format("%s [label=\"%s: %s\"]%n", n.getId(), n.getId(), n.getDisplayName())); 61 | } 62 | 63 | buffer.append("}"); 64 | return buffer.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/Constants.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | public class Constants { 9 | public static final String TESTCASE = "testcase"; 10 | public static final String TESTSUITE = "testsuite"; 11 | public static final String BUILD_ID = "build_url"; 12 | public static final String TAG = "event_tag"; 13 | public static final String JOB_RESULT = "job_result"; 14 | public static final String JSON_ENDPOINT = "/services/collector/event"; 15 | public static final String RAW_ENDPOINT = "/services/collector/raw"; 16 | public static final String LOG_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; 17 | public final static String SLAVE_TAG_NAME = "slave"; 18 | public final static String QUEUE_TAG_NAME = "queue"; 19 | public final static String QUEUE_WAITING_ITEM_NAME = "queue_item"; 20 | public static final String JOB_EVENT_TAG_NAME = "job_event"; 21 | public static final String JOB_EVENT_MONITOR = "job_monitor"; 22 | public static final String MASTER = "(master)"; 23 | public static final String BUILD_REPORT_ENV_TAG = "metadata"; 24 | public static final String JENKINS_CONFIG_PREFIX = "jenkins://"; 25 | public static final String JENKINS_SOURCE_SEP = "/"; 26 | public static final String AUDIT_SOURCE = "audit_trail"; 27 | public static final String USER_NAME_KEY = "user"; 28 | public static final String EVENT_CAUSED_BY = "event_src"; 29 | public static final String EVENT_SOURCE_TYPE = "sourcetype"; 30 | public static final String NODE_NAME = "node_name"; 31 | public static final String ERROR_MESSAGE_NA = "(none)"; 32 | public static final String MASK_PASSWORD = "***"; 33 | public static final String NO_TEST_REPORT_FOUND = "No TestResult"; 34 | public static final String TEST_REPORT_NOT_CONFIGURED = "Junit or xUnit report not configured"; 35 | public static final ImmutableList SCRIPT_TEXT_MD5_HASH = ImmutableList.of("729ac3b82ecf2e0afc0cb00d73c22892", 36 | "f43916477139eb890e72c1602e0851b4", "aac4abe92db9bf90e3b27a4e41728526"); 37 | // min buffer size for raw data (usually log file and console) 38 | public static final int MIN_BUFFER_SIZE = Integer.getInteger("splunkins.buffer", 4096); 39 | public static final int JDK_FINE_LOG_BATCH = Integer.getInteger("splunkins.debugLogBatchSize", 128); 40 | // max buffer size for raw data (usually log file and console) 41 | public static final int MAX_BATCH_SIZE = 1 << 23; 42 | // use gzip for http posting 43 | public static final int GZIP_THRESHOLD = 1024; //1kb 44 | // 16 KB for slave log 45 | public static final int SLAVE_LOG_BUFFER_SIZE = MIN_BUFFER_SIZE * 4; 46 | public static final String COVERAGE_OVERALL_NAME = "project"; 47 | // maximum line length (very long lines are, however, often a sign of garbage data) 48 | // if it is increased, please also increase the TRUNCATE config in splunk props.conf 49 | // ref: http://docs.splunk.com/Documentation/Splunk/7.2.1/Admin/Propsconf 50 | public static final int CONSOLE_TEXT_SINGLE_LINE_MAX_LENGTH = Integer.getInteger("splunkins.lineTruncate", 100000); 51 | } 52 | -------------------------------------------------------------------------------- /doc/extension.md: -------------------------------------------------------------------------------- 1 | Plugin implements some interfaces and mark the implementation to use annotation @Extension so Jenkins can load it dynamically 2 | 3 | # Configure 4 | 5 | ### SplunkJenkinsInstallation 6 | package com.splunk.splunkjenkins 7 | Follow jenkins conventions, using java bean property host, port, token, useSSL, scriptPath etc and some helper method such as 8 | doCheckHost to validate host, doTestHttpInput to verify connection, see also https://wiki.jenkins-ci. org/display/JENKINS/Form+Validation 9 | 10 | # Function 11 | ### Listeners 12 | package com.splunk.splunkjenkins.listeners, receives notifications from jenkins, for example in Jenkins delete job action 13 | ``` 14 | /** 15 | * Called in response to {@link Job#doDoDelete(StaplerRequest, StaplerResponse)} 16 | */ 17 | public void onDeleted(TopLevelItem item) throws IOException { 18 | ItemListener.fireOnDeleted(item); 19 | 20 | items.remove(item.getName()); 21 | // For compatibility with old views: 22 | for (View v : views) 23 | v.onJobRenamed(item, item.getName(), null); 24 | } 25 | 26 | ``` 27 | it will call fireOnDeleted to notify all ItemListeners 28 | 29 | ## Listeners list 30 | #### [SecurityListener](http://javadoc.jenkins-ci.org/jenkins/security/SecurityListener.html) 31 | record user login/logout and failedToLogIn events 32 | #### [SaveableListener](http://javadoc.jenkins-ci.org/hudson/model/listeners/SaveableListener.html) 33 | when user made changes to jenkins config (either plugin config or job config), record the config xml. disabled by default until user add jenkins_config.monitoring=true into metadata config 34 | #### [ItemListener](http://javadoc.jenkins-ci.org/hudson/model/listeners/RunListener.html) 35 | similar to SaveableListener but for Job only, it has finer grained audit event. used to capture job created, renamed, copied and deleted 36 | 37 | #### [QueueListener](http://javadoc.jenkins-ci.org/hudson/model/queue/QueueListener.html) 38 | listen for onEnterWaiting and onLeft and record the job queueTime and jenkins metrics 39 | #### [RunListener](http://javadoc.jenkins-ci.org/hudson/model/listeners/RunListener.html) 40 | listen for onStarted and onCompleted, and extract upstream job, build cause, scm, job result, and invoke DSL if defined 41 | #### [ComputerListener](http://javadoc.jenkins-ci.org/hudson/slaves/ComputerListener.html) 42 | record slave online, offline, temporarilyOffline, and launchFailure 43 | 44 | ## [Notifier](http://javadoc.jenkins-ci.org/hudson/tasks/Notifier.html) 45 | Contribute to post build step, user can custom the logs to send to splunk in addition to what we have in Groovy DSL. 46 | 47 | ## Links 48 | ### RootAction 49 | add link to home page 50 | ### ManagementLink 51 | add link to management page 52 | ### TransientComputerActionFactory 53 | and link to other types, such as Build, Computer 54 | 55 | ## Task 56 | we extends AsyncPeriodicWork to run tasks periodic to gather agent metrics 57 | 58 | # Service 59 | SplunkLogService launched two threads to drain the splunk event queue, used (Splunk HTTP Event Collector)[http://dev.splunk.com/view/event-collector/SP-CAAAE6M] to pump data into splunk, message format 60 | 61 | ``` 62 | 63 | { 64 | "time": 1426279439, 65 | "host": "localhost", 66 | "source": "datasource", 67 | "sourcetype": "txt", 68 | "index": "main", 69 | "event": { jenkins_event_json_here } 70 | } 71 | 72 | ``` 73 | 74 | -------------------------------------------------------------------------------- /splunk-devops/src/test/java/com/splunk/splunkjenkins/SplunkLogServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.UUID; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.logging.Logger; 9 | 10 | import com.splunk.splunkjenkins.model.EventType; 11 | import com.splunk.splunkjenkins.utils.SplunkLogService; 12 | import org.junit.*; 13 | 14 | import static com.splunk.splunkjenkins.SplunkConfigUtil.verifySplunkSearchResult; 15 | import static org.junit.Assert.*; 16 | 17 | import javax.annotation.concurrent.NotThreadSafe; 18 | 19 | @NotThreadSafe 20 | public class SplunkLogServiceTest extends BaseTest { 21 | private static final Logger LOG = Logger.getLogger(SplunkLogServiceTest.class.getName()); 22 | private static final int BATCH_COUNT = 1000; 23 | 24 | /** 25 | * Test of update method, of class SplunkLogService. 26 | */ 27 | @Test 28 | public void testLogServiceSendMethod() throws IOException, InterruptedException { 29 | LOG.info("running test SplunkLogServiceTest testLogServiceSendMethod"); 30 | assertTrue("config should be valid", SplunkJenkinsInstallation.get().isValid()); 31 | String line = "127.0.0.1 - admin \"GET /en-US/ HTTP/1.1\""; 32 | boolean queuedGenericMessage = SplunkLogService.getInstance().send(line); 33 | assertTrue("should put message in queue", queuedGenericMessage); 34 | long timestamp = System.currentTimeMillis(); 35 | String query = "index=" + SplunkConfigUtil.INDEX_NAME + " |spath batch|where batch=" + timestamp; 36 | LOG.info(query); 37 | long initNumber = SplunkLogService.getInstance().getSentCount(); 38 | for (int i = 0; i < BATCH_COUNT; i++) { 39 | Map data = new HashMap(); 40 | data.put("id", UUID.randomUUID().toString()); 41 | data.put("batch", timestamp); 42 | data.put("number", i); 43 | boolean queued = SplunkLogService.getInstance().send(data); 44 | assertTrue("should put the message to queue", queued); 45 | } 46 | //give some time to send,max wait time is 3 minute 47 | long timeToWait = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(3); 48 | while (SplunkLogService.getInstance().getSentCount() < (BATCH_COUNT + initNumber)) { 49 | Thread.sleep(1000); 50 | long queueSize = SplunkLogService.getInstance().getQueueSize(); 51 | long sentCount = SplunkLogService.getInstance().getSentCount(); 52 | long remaining = BATCH_COUNT + initNumber - sentCount; 53 | LOG.fine("queue size:" + queueSize + " sent:" + sentCount); 54 | if (System.currentTimeMillis() > timeToWait) { 55 | fail("can not send events in time, remaining " + remaining); 56 | } 57 | } 58 | int expected = BATCH_COUNT; 59 | verifySplunkSearchResult(query, timestamp, expected); 60 | } 61 | 62 | @Test 63 | public void sendFloatNaN() { 64 | Map result = new HashMap(); 65 | result.put("floatNaN", Float.NaN); 66 | result.put("doubleMaxVal", Double.MAX_VALUE); 67 | result.put("doubleMinVal", Double.MIN_VALUE); 68 | result.put("doubleNaN", Double.NaN); 69 | long timestamp = System.currentTimeMillis(); 70 | SplunkLogService.getInstance().send(result, EventType.LOG); 71 | String query = "doubleMaxVal>9999999999999999"; 72 | verifySplunkSearchResult(query, timestamp, 1); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /splunk-devops-shaded/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.splunk.splunkins 7 | pom 8 | 1.7.5-SNAPSHOT 9 | 10 | 11 | splunk-devops-shaded 12 | jar 13 | 14 | Shaded http client and gson jar 15 | 16 | 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-shade-plugin 21 | 2.4.3 22 | 23 | 24 | package 25 | 26 | shade 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | true 35 | 36 | 37 | org.apache.httpcomponents:* 38 | com.google.code.gson:gson 39 | 40 | 41 | 42 | 43 | org.apache.http 44 | shaded.splk.org.apache.http 45 | 46 | 47 | com.google.gson 48 | shaded.splk.com.google.gson 49 | 50 | 51 | true 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.httpcomponents 63 | httpcore 64 | 4.4.9 65 | 66 | 67 | org.apache.httpcomponents 68 | httpclient 69 | 4.5.5 70 | 71 | 72 | com.google.code.gson 73 | gson 74 | 2.6.2 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/listeners/LoggingQueueListener.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.listeners; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.splunk.splunkjenkins.Constants; 6 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 7 | import com.splunk.splunkjenkins.utils.SplunkLogService; 8 | import hudson.Extension; 9 | import hudson.model.Queue; 10 | import hudson.model.queue.QueueListener; 11 | 12 | import java.util.Map; 13 | 14 | import static com.splunk.splunkjenkins.model.EventType.QUEUE_INFO; 15 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getMasterStats; 16 | 17 | /** 18 | *
{@code from jenkins javadoc
 19 |  *  (enter) --> waitingList --+--> blockedProjects
 20 |  *                            |        ^
 21 |  *                            |        |
 22 |  *                            |        v
 23 |  *                            +--> buildables ---> pending ---> left
 24 |  *                                     ^              |
 25 |  *                                     |              |
 26 |  *                                     +---(rarely)---+
 27 |  *
 28 |  * }
29 | */ 30 | @SuppressWarnings("unused") 31 | @Extension 32 | public class LoggingQueueListener extends QueueListener { 33 | private final static Cache cache = CacheBuilder.newBuilder() 34 | .maximumSize(3000).build(); 35 | 36 | @Override 37 | public void onEnterWaiting(Queue.WaitingItem wi) { 38 | if (SplunkJenkinsInstallation.get().isEventDisabled(QUEUE_INFO)) { 39 | return; 40 | } 41 | String name = getTaskName(wi.task); 42 | if (SplunkJenkinsInstallation.get().isJobIgnored(name)) { 43 | return; 44 | } 45 | Map event = getMasterStats(); 46 | event.put("item", name); 47 | event.put(Constants.TAG, Constants.QUEUE_TAG_NAME); 48 | event.put("type", "enqueue"); 49 | SplunkLogService.getInstance().send(event, QUEUE_INFO); 50 | } 51 | 52 | @Override 53 | public void onLeft(Queue.LeftItem li) { 54 | if (SplunkJenkinsInstallation.get().isEventDisabled(QUEUE_INFO)) { 55 | return; 56 | } 57 | String name = getTaskName(li.task); 58 | if (SplunkJenkinsInstallation.get().isJobIgnored(name)) { 59 | return; 60 | } 61 | float queueTime = (System.currentTimeMillis() - li.getInQueueSince()) / 1000f; 62 | cache.put(li.getId(), queueTime); 63 | Map event = getMasterStats(); 64 | event.put("item", name); 65 | event.put(Constants.TAG, Constants.QUEUE_TAG_NAME); 66 | event.put("queue_id", li.getId()); 67 | event.put("queue_time", queueTime); 68 | event.put("type", "dequeue"); 69 | SplunkLogService.getInstance().send(event, QUEUE_INFO); 70 | } 71 | 72 | /** 73 | * queue task only have project name, don't have build number 74 | * 75 | * @param task Queue task 76 | * @return task name 77 | */ 78 | public String getTaskName(Queue.Task task) { 79 | if (task == null) { 80 | return "n/a"; 81 | } else { 82 | return task.getUrl(); 83 | } 84 | } 85 | 86 | public static Float getQueueTime(Long Id) { 87 | Float queueTime= cache.getIfPresent(Id); 88 | if (queueTime == null) { 89 | //the queue has been garbage collected 90 | queueTime = 0f; 91 | } 92 | return queueTime; 93 | } 94 | 95 | public static void expire(Long Id) { 96 | cache.invalidate(Id); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/Clover/workspace/clover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/com/splunk/splunkjenkins/SplunkJenkinsInstallation/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 57 | 58 | 59 | 60 | 63 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/TestCaseResult.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.tasks.test.TestObject; 4 | import hudson.tasks.test.TestResult; 5 | 6 | public class TestCaseResult extends TestResult { 7 | private float duration; 8 | private String className; 9 | private String testName; 10 | private String groupName; 11 | private boolean skipped; 12 | private String skippedMessage; 13 | private String errorStackTrace; 14 | private String errorDetails; 15 | private String stdout, stderr; 16 | private int failedSince; 17 | private String uniqueName; 18 | private TestStatus status; 19 | 20 | @Override 21 | public TestObject getParent() { 22 | return null; 23 | } 24 | 25 | @Override 26 | public TestResult findCorrespondingResult(String id) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public String getDisplayName() { 32 | return null; 33 | } 34 | 35 | @Override 36 | public float getDuration() { 37 | return duration; 38 | } 39 | 40 | public void setDuration(float duration) { 41 | this.duration = duration; 42 | } 43 | 44 | public String getClassName() { 45 | return className; 46 | } 47 | 48 | public void setClassName(String className) { 49 | this.className = className; 50 | } 51 | 52 | public String getTestName() { 53 | return testName; 54 | } 55 | 56 | public void setTestName(String testName) { 57 | this.testName = testName; 58 | } 59 | 60 | public boolean isSkipped() { 61 | return skipped; 62 | } 63 | 64 | public void setSkipped(boolean skipped) { 65 | this.skipped = skipped; 66 | } 67 | 68 | public String getSkippedMessage() { 69 | return skippedMessage; 70 | } 71 | 72 | public void setSkippedMessage(String skippedMessage) { 73 | this.skippedMessage = skippedMessage; 74 | } 75 | 76 | @Override 77 | public String getErrorStackTrace() { 78 | return errorStackTrace; 79 | } 80 | 81 | public void setErrorStackTrace(String errorStackTrace) { 82 | this.errorStackTrace = errorStackTrace; 83 | } 84 | 85 | @Override 86 | public String getErrorDetails() { 87 | return errorDetails; 88 | } 89 | 90 | public void setErrorDetails(String errorDetails) { 91 | this.errorDetails = errorDetails; 92 | } 93 | 94 | @Override 95 | public String getStdout() { 96 | return stdout; 97 | } 98 | 99 | public void setStdout(String stdout) { 100 | this.stdout = stdout; 101 | } 102 | 103 | @Override 104 | public String getStderr() { 105 | return stderr; 106 | } 107 | 108 | public void setStderr(String stderr) { 109 | this.stderr = stderr; 110 | } 111 | 112 | @Override 113 | public int getFailedSince() { 114 | return failedSince; 115 | } 116 | 117 | public void setFailedSince(int failedSince) { 118 | this.failedSince = failedSince; 119 | } 120 | 121 | public String getUniqueName() { 122 | return uniqueName; 123 | } 124 | 125 | public void setUniqueName(String uniqueName) { 126 | this.uniqueName = uniqueName; 127 | } 128 | 129 | public TestStatus getStatus() { 130 | return status; 131 | } 132 | 133 | public void setStatus(TestStatus status) { 134 | this.status = status; 135 | } 136 | 137 | @Override 138 | public int getPassCount() { 139 | return TestStatus.PASSED == status ? 1 : 0; 140 | } 141 | 142 | @Override 143 | public int getFailCount() { 144 | return TestStatus.FAILURE == status ? 1 : 0; 145 | } 146 | 147 | @Override 148 | public int getSkipCount() { 149 | return TestStatus.SKIPPED == status ? 1 : 0; 150 | } 151 | 152 | public String getGroupName() { 153 | return groupName; 154 | } 155 | 156 | public void setGroupName(String groupName) { 157 | this.groupName = groupName; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/java/com/splunk/splunkjenkins/SplunkLogFileStep.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import hudson.EnvVars; 5 | import hudson.Extension; 6 | import hudson.FilePath; 7 | import hudson.model.Run; 8 | import hudson.model.TaskListener; 9 | import org.jenkinsci.plugins.workflow.steps.Step; 10 | import org.jenkinsci.plugins.workflow.steps.StepContext; 11 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor; 12 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 13 | import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; 14 | import org.kohsuke.stapler.DataBoundConstructor; 15 | import org.kohsuke.stapler.DataBoundSetter; 16 | 17 | import javax.annotation.Nonnull; 18 | import java.util.Set; 19 | 20 | import static com.splunk.splunkjenkins.utils.LogEventHelper.parseFileSize; 21 | import static com.splunk.splunkjenkins.utils.LogEventHelper.sendFiles; 22 | 23 | /** 24 | * Send logs to splunk 25 | */ 26 | public class SplunkLogFileStep extends Step { 27 | //required fields 28 | String includes; 29 | 30 | @DataBoundSetter 31 | String sizeLimit; 32 | @DataBoundSetter 33 | String excludes; 34 | @DataBoundSetter 35 | boolean publishFromSlave; 36 | 37 | @DataBoundConstructor 38 | public SplunkLogFileStep(@Nonnull String includes) { 39 | this.includes = includes; 40 | } 41 | 42 | @Override 43 | public StepExecution start(StepContext context) throws Exception { 44 | return new SplunkLogFileStepExecution(context, this); 45 | } 46 | 47 | public String getIncludes() { 48 | return includes; 49 | } 50 | 51 | public void setIncludes(String includes) { 52 | this.includes = includes; 53 | } 54 | 55 | public String getExcludes() { 56 | return excludes; 57 | } 58 | 59 | public void setExcludes(String excludes) { 60 | this.excludes = excludes; 61 | } 62 | 63 | public boolean isPublishFromSlave() { 64 | return publishFromSlave; 65 | } 66 | 67 | public void setPublishFromSlave(boolean publishFromSlave) { 68 | this.publishFromSlave = publishFromSlave; 69 | } 70 | 71 | public String getSizeLimit() { 72 | return sizeLimit; 73 | } 74 | 75 | public void setSizeLimit(String sizeLimit) { 76 | this.sizeLimit = sizeLimit; 77 | } 78 | 79 | @Extension 80 | public static class DescriptorImpl extends StepDescriptor { 81 | 82 | @Override 83 | public Set> getRequiredContext() { 84 | return ImmutableSet.of(Run.class, TaskListener.class, FilePath.class, EnvVars.class); 85 | } 86 | 87 | @Override 88 | public String getFunctionName() { 89 | return "sendSplunkFile"; 90 | } 91 | 92 | @Nonnull 93 | @Override 94 | public String getDisplayName() { 95 | return "Send files to Splunk"; 96 | } 97 | } 98 | 99 | public static class SplunkLogFileStepExecution extends SynchronousNonBlockingStepExecution { 100 | protected SplunkLogFileStepExecution(StepContext context, SplunkLogFileStep step) throws Exception { 101 | super(context); 102 | this.step = step; 103 | } 104 | 105 | private static final long serialVersionUID = 1152009261375345133L; 106 | private transient SplunkLogFileStep step; 107 | 108 | @Override 109 | protected Void run() throws Exception { 110 | if (!SplunkJenkinsInstallation.get().isEnabled()) { 111 | return null; 112 | } 113 | TaskListener listener = getContext().get(TaskListener.class); 114 | FilePath workspace = getContext().get(FilePath.class); 115 | Run build = getContext().get(Run.class); 116 | EnvVars envVars = getContext().get(EnvVars.class); 117 | sendFiles(build, workspace, envVars, listener, 118 | step.includes, step.excludes, step.publishFromSlave, parseFileSize(step.sizeLimit)); 119 | return null; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/CloverCoverageMetrics.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.Extension; 4 | import hudson.plugins.clover.CloverBuildAction; 5 | import hudson.plugins.clover.Ratio; 6 | import hudson.plugins.clover.results.*; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static com.splunk.splunkjenkins.Constants.COVERAGE_OVERALL_NAME; 14 | 15 | /** 16 | * CoverageMetric for
clover 17 | */ 18 | @Extension(optional = true) 19 | public class CloverCoverageMetrics extends CoverageMetricsAdapter { 20 | /** 21 | * @return coverage summary 22 | * {@inheritDoc} 23 | */ 24 | @Override 25 | public Map getMetrics(CloverBuildAction coverageAction) { 26 | ProjectCoverage projectCoverage = coverageAction.getResult(); 27 | Map result = extract(projectCoverage); 28 | return result; 29 | } 30 | 31 | @Override 32 | public List getReport(CloverBuildAction coverageAction) { 33 | ProjectCoverage projectCoverage = coverageAction.getResult(); 34 | List result = new ArrayList<>(); 35 | CoverageDetail summary = new CoverageDetail(COVERAGE_OVERALL_NAME, CoverageLevel.PROJECT); 36 | result.add(summary); 37 | appendDetail(summary, coverageAction); 38 | for (PackageCoverage pcover : projectCoverage.getChildren()) { 39 | CoverageDetail packageDetail = new CoverageDetail(pcover.getName(), CoverageLevel.PACKAGE); 40 | result.add(packageDetail); 41 | appendDetail(packageDetail, pcover); 42 | for (FileCoverage fcover : pcover.getChildren()) { 43 | CoverageDetail fileDetail = new CoverageDetail(pcover.getName(), CoverageLevel.FILE); 44 | result.add(fileDetail); 45 | appendDetail(fileDetail, fcover); 46 | for (ClassCoverage clazzCover : fcover.getChildren()) { 47 | CoverageDetail clazzDetail = new CoverageDetail(clazzCover.getName(), CoverageLevel.CLASS); 48 | result.add(clazzDetail); 49 | appendDetail(clazzDetail, clazzCover); 50 | } 51 | } 52 | } 53 | return result; 54 | } 55 | 56 | private Map extract(AbstractCloverMetrics coverageObject) { 57 | Map result = new HashMap<>(); 58 | putMetricIfExists(result, Metric.METHOD, coverageObject.getMethodCoverage()); 59 | putMetricIfExists(result, Metric.STATEMENT, coverageObject.getStatementCoverage()); 60 | putMetricIfExists(result, Metric.CONDITIONAL, coverageObject.getConditionalCoverage()); 61 | putMetricIfExists(result, Metric.ELEMENT, coverageObject.getElementCoverage()); 62 | return result; 63 | } 64 | 65 | private void putMetricIfExists(Map result, Metric metric, Ratio ratio) { 66 | if (ratio.denominator > 0) { 67 | result.put(metric, ratio.getPercentage()); 68 | } 69 | } 70 | 71 | /** 72 | * get detail report about percentage, covered, and total number 73 | * 74 | * @param detail 75 | * @param coverageObject 76 | */ 77 | private void appendDetail(CoverageDetail detail, AbstractCloverMetrics coverageObject) { 78 | appendDetail(detail, Metric.METHOD, coverageObject.getMethodCoverage()); 79 | appendDetail(detail, Metric.STATEMENT, coverageObject.getStatementCoverage()); 80 | appendDetail(detail, Metric.CONDITIONAL, coverageObject.getConditionalCoverage()); 81 | appendDetail(detail, Metric.ELEMENT, coverageObject.getElementCoverage()); 82 | } 83 | 84 | private void appendDetail(CoverageDetail detail, Metric metricName, Ratio ratio) { 85 | if (ratio.denominator == 0) { 86 | return; 87 | } 88 | detail.add(metricName + PERCENTAGE_SUFFIX, ratio.getPercentage()); 89 | detail.add(metricName + TOTAL_SUFFIX, (int) ratio.denominator); 90 | detail.add(metricName + COVERED_SUFFIX, (int) ratio.numerator); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/SplunkArtifactNotifier.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import hudson.Extension; 4 | import hudson.FilePath; 5 | import hudson.Launcher; 6 | import hudson.model.*; 7 | import hudson.tasks.BuildStepDescriptor; 8 | import hudson.tasks.BuildStepMonitor; 9 | import hudson.tasks.Notifier; 10 | import hudson.tasks.Publisher; 11 | import jenkins.tasks.SimpleBuildStep; 12 | import org.kohsuke.stapler.DataBoundConstructor; 13 | 14 | import javax.annotation.Nonnull; 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import static com.splunk.splunkjenkins.utils.LogEventHelper.parseFileSize; 22 | import static com.splunk.splunkjenkins.utils.LogEventHelper.sendFiles; 23 | 24 | @SuppressWarnings("unused") 25 | public class SplunkArtifactNotifier extends Notifier implements SimpleBuildStep { 26 | /** 27 | * {@link org.apache.tools.ant.types.FileSet} "includes" string, like "foo/bar/*.xml" 28 | */ 29 | private final String includeFiles; 30 | private final String excludeFiles; 31 | private final boolean publishFromSlave; 32 | private final boolean skipGlobalSplunkArchive; 33 | private final String sizeLimit; 34 | 35 | @DataBoundConstructor 36 | public SplunkArtifactNotifier(String includeFiles, String excludeFiles, boolean publishFromSlave, 37 | boolean skipGlobalSplunkArchive, String sizeLimit) { 38 | this.includeFiles = includeFiles; 39 | this.excludeFiles = excludeFiles; 40 | this.publishFromSlave = publishFromSlave; 41 | this.skipGlobalSplunkArchive = skipGlobalSplunkArchive; 42 | this.sizeLimit=sizeLimit; 43 | } 44 | 45 | @Override 46 | public BuildStepMonitor getRequiredMonitorService() { 47 | return BuildStepMonitor.NONE; 48 | } 49 | 50 | @Override 51 | public void perform(@Nonnull Run build, @Nonnull FilePath workspace, 52 | @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws InterruptedException, IOException { 53 | Map envVars = new HashMap<>(); 54 | try { 55 | envVars = build.getEnvironment(listener); 56 | } catch (Exception ex) { 57 | listener.getLogger().println("failed to get env"); 58 | } 59 | long maxFileSize=parseFileSize(sizeLimit); 60 | listener.getLogger().println("sending files at job level, includes:" + includeFiles + " excludes:" + excludeFiles); 61 | int eventCount = sendFiles(build, workspace, envVars, listener, includeFiles, excludeFiles, publishFromSlave, maxFileSize); 62 | Logger.getLogger(this.getClass().getName()).log(Level.FINE,"sent "+eventCount+" events with file size limit "+maxFileSize); 63 | } 64 | 65 | @Extension 66 | public static class DescriptorImpl extends BuildStepDescriptor { 67 | @Override 68 | public boolean isApplicable(@SuppressWarnings("rawtypes") Class jobType) { 69 | return true; 70 | } 71 | 72 | public String getDisplayName() { 73 | return Messages.SplunArtifactArchive(); 74 | } 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return "SplunkArtifactNotifier{" + 80 | "includeFiles='" + includeFiles + '\'' + 81 | ", excludeFiles='" + excludeFiles + '\'' + 82 | ", publishFromSlave=" + publishFromSlave + 83 | ", skipGlobalSplunkArchive=" + skipGlobalSplunkArchive + 84 | ", sizeLimit='" + sizeLimit + '\'' + 85 | '}'; 86 | } 87 | 88 | public String getIncludeFiles() { 89 | return includeFiles; 90 | } 91 | 92 | public String getExcludeFiles() { 93 | return excludeFiles; 94 | } 95 | 96 | public boolean isPublishFromSlave() { 97 | return publishFromSlave; 98 | } 99 | 100 | public boolean isSkipGlobalSplunkArchive() { 101 | return skipGlobalSplunkArchive; 102 | } 103 | 104 | public String getSizeLimit() { 105 | return sizeLimit; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/CoverageMetricTest/jobs/Cobertura/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | false 9 | 10 | 11 | false 12 | false 13 | 14 | 15 | 0 16 | 0 17 | 18 | false 19 | project 20 | 21 | 22 | 23 | true 24 | false 25 | false 26 | false 27 | 28 | false 29 | 30 | 31 | 32 | coverage.xml 33 | false 34 | false 35 | false 36 | false 37 | false 38 | false 39 | 0 40 | true 41 | 42 | 43 | 44 | METHOD 45 | 8000000 46 | 47 | 48 | LINE 49 | 8000000 50 | 51 | 52 | CONDITIONAL 53 | 7000000 54 | 55 | 56 | 57 | 58 | 59 | 60 | METHOD 61 | 0 62 | 63 | 64 | LINE 65 | 0 66 | 67 | 68 | CONDITIONAL 69 | 0 70 | 71 | 72 | 73 | 74 | 75 | 76 | METHOD 77 | 0 78 | 79 | 80 | LINE 81 | 0 82 | 83 | 84 | CONDITIONAL 85 | 0 86 | 87 | 88 | 89 | ASCII 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/listeners/LoggingConfigListener.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.listeners; 2 | 3 | import com.splunk.splunkjenkins.SplunkJenkinsInstallation; 4 | import com.splunk.splunkjenkins.utils.SplunkLogService; 5 | import hudson.Extension; 6 | import hudson.XmlFile; 7 | import hudson.model.Item; 8 | import hudson.model.Saveable; 9 | import hudson.model.User; 10 | import hudson.model.listeners.SaveableListener; 11 | import jenkins.model.Jenkins; 12 | import org.apache.commons.codec.digest.DigestUtils; 13 | 14 | import java.io.IOException; 15 | import java.util.WeakHashMap; 16 | import java.util.logging.Level; 17 | import java.util.logging.Logger; 18 | import java.util.regex.Pattern; 19 | import java.util.regex.PatternSyntaxException; 20 | 21 | import static com.splunk.splunkjenkins.Constants.JENKINS_CONFIG_PREFIX; 22 | import static com.splunk.splunkjenkins.model.EventType.JENKINS_CONFIG; 23 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getRelativeJenkinsHomePath; 24 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getUserName; 25 | import static com.splunk.splunkjenkins.utils.LogEventHelper.logUserAction; 26 | 27 | /** 28 | * record jenkins config and job changes 29 | * send config content to splunk 30 | */ 31 | 32 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("VA_FORMAT_STRING_USES_NEWLINE") 33 | @Extension 34 | public class LoggingConfigListener extends SaveableListener { 35 | private static final String XML_COMMENT = "\n"; 36 | private static final Logger LOGGER = Logger.getLogger(LoggingConfigListener.class.getName()); 37 | //queue.xml or build/*/config.xml 38 | private static final String IGNORE_CONFIG_CHANGE_PATTERN = "(queue|nodeMonitors|UpdateCenter|global-build-stats" + 39 | "|fingerprint|build)(.*?xml)"; 40 | private static final Pattern IGNORED; 41 | 42 | static { 43 | String ignorePatternStr = System.getProperty("splunkins.ignoreConfigChangePattern", IGNORE_CONFIG_CHANGE_PATTERN); 44 | Pattern ignorePattern; 45 | try { 46 | ignorePattern = Pattern.compile(ignorePatternStr, Pattern.CASE_INSENSITIVE); 47 | } catch (PatternSyntaxException ex) { 48 | ignorePattern = Pattern.compile(IGNORE_CONFIG_CHANGE_PATTERN, Pattern.CASE_INSENSITIVE); 49 | } 50 | IGNORED = ignorePattern; 51 | } 52 | 53 | private WeakHashMap cached = new WeakHashMap(512); 54 | 55 | @Override 56 | public void onChange(Saveable saveable, XmlFile file) { 57 | if (!SplunkJenkinsInstallation.isLogHandlerRegistered()) { 58 | return; 59 | } 60 | String configPath = file.getFile().getAbsolutePath(); 61 | if (saveable == null || IGNORED.matcher(configPath).find()) { 62 | LOGGER.log(Level.FINE, "{} is ignored", configPath); 63 | return; 64 | } 65 | if (saveable instanceof User) { 66 | //we use SecurityListener to capture login/logout events 67 | return; 68 | } 69 | if (SplunkJenkinsInstallation.get().isEventDisabled(JENKINS_CONFIG)) { 70 | return; 71 | } 72 | //log audit trail, excludes Item instances which were already tracked by other listener 73 | String relativePath = getRelativeJenkinsHomePath(configPath); 74 | if (!(saveable instanceof Item)) { 75 | logUserAction(getUserName(), Messages.audit_update_item(relativePath)); 76 | } 77 | if ("SYSTEM".equals(Jenkins.getAuthentication().getName())) { 78 | LOGGER.log(Level.FINE, "{0} is changed by system", configPath); 79 | //ignore changes made by daemons or background jobs 80 | return; 81 | } 82 | try { 83 | String configContent = file.asString(); 84 | String checkSum = DigestUtils.md5Hex(configPath + configContent); 85 | if (cached.containsKey(checkSum)) { 86 | //Save a job can trigger multiple SaveableListener, depends on jenkins versions 87 | // e.g. AbstractProject.submit may call setters which can trigger save() 88 | return; 89 | } 90 | cached.put(checkSum, 0); 91 | String sourceName = JENKINS_CONFIG_PREFIX + relativePath; 92 | String userName = getUserName(); 93 | String comment = String.format(XML_COMMENT, userName); 94 | SplunkLogService.getInstance().send(comment + configContent, JENKINS_CONFIG, sourceName); 95 | } catch (IOException e) { 96 | //just ignore 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/CoberturaCoverageMetrics.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.Extension; 4 | import hudson.plugins.cobertura.CoberturaBuildAction; 5 | import hudson.plugins.cobertura.Ratio; 6 | import hudson.plugins.cobertura.targets.CoverageElement; 7 | import hudson.plugins.cobertura.targets.CoverageMetric; 8 | import hudson.plugins.cobertura.targets.CoverageResult; 9 | 10 | import java.util.*; 11 | 12 | import static com.splunk.splunkjenkins.Constants.COVERAGE_OVERALL_NAME; 13 | 14 | /** 15 | * CoverageMetric for Cobertura 16 | */ 17 | @Extension(optional = true) 18 | public class CoberturaCoverageMetrics extends CoverageMetricsAdapter { 19 | private static List TOP_LEVELS = Arrays.asList(CoverageElement.PROJECT, 20 | CoverageElement.JAVA_PACKAGE, CoverageElement.JAVA_FILE); 21 | 22 | /** 23 | * @return coverage summary 24 | * {@inheritDoc} 25 | */ 26 | @Override 27 | public Map getMetrics(CoberturaBuildAction coverageAction) { 28 | return extract(coverageAction.getResult()); 29 | } 30 | 31 | private Map extract(CoverageResult coverageResult) { 32 | Map result = new HashMap<>(); 33 | Set metrics = coverageResult.getMetrics(); 34 | for (CoverageMetric metric : metrics) { 35 | Metric reportMetric = Metric.getMetric(metric.name()); 36 | if (reportMetric != null) { 37 | Ratio ratio = coverageResult.getCoverage(metric); 38 | if (ratio.denominator > 0) { 39 | int percentage = ratio.getPercentage(); 40 | result.put(reportMetric, percentage); 41 | } 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | private void appendDetail(CoverageDetail detail, CoverageResult coverageResult) { 48 | Set metrics = coverageResult.getMetrics(); 49 | for (CoverageMetric metric : metrics) { 50 | Metric reportMetric = Metric.getMetric(metric.name()); 51 | if (reportMetric != null) { 52 | Ratio ratio = coverageResult.getCoverage(metric); 53 | if (ratio.denominator > 0) { 54 | detail.add(reportMetric + PERCENTAGE_SUFFIX, ratio.getPercentage()); 55 | detail.add(reportMetric + TOTAL_SUFFIX, (int) ratio.denominator); 56 | detail.add(reportMetric + COVERED_SUFFIX, (int) ratio.numerator); 57 | } 58 | } 59 | } 60 | } 61 | 62 | @Override 63 | public List getReport(CoberturaBuildAction coverageAction) { 64 | CoverageResult coverageResult = coverageAction.getResult(); 65 | return getReport(coverageResult, ""); 66 | } 67 | 68 | private List getReport(CoverageResult coverage, String prefix) { 69 | List report = new ArrayList<>(); 70 | CoverageLevel level; 71 | prefix = prefix == null ? "" : prefix; 72 | String coverageName = prefix + coverage.getName(); 73 | String childPrefix = prefix; 74 | switch (coverage.getElement()) { 75 | case JAVA_FILE: 76 | level = CoverageLevel.FILE; 77 | break; 78 | case JAVA_PACKAGE: 79 | level = CoverageLevel.PACKAGE; 80 | childPrefix = coverageName + "."; 81 | break; 82 | case PROJECT: 83 | level = CoverageLevel.PROJECT; 84 | coverageName = COVERAGE_OVERALL_NAME; 85 | break; 86 | case JAVA_METHOD: 87 | level = CoverageLevel.METHOD; 88 | break; 89 | case JAVA_CLASS: 90 | level = CoverageLevel.CLASS; 91 | childPrefix = coverageName + "#"; 92 | break; 93 | default: 94 | level = CoverageLevel.PACKAGE; 95 | } 96 | CoverageDetail detail = new CoverageDetail(coverageName, level); 97 | appendDetail(detail, coverage); 98 | report.add(detail); 99 | Map children = coverage.getChildrenReal(); 100 | if (children == null || children.isEmpty()) { 101 | return report; 102 | } 103 | for (CoverageResult child : children.values()) { 104 | report.addAll(getReport(child, childPrefix)); 105 | } 106 | return report; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /splunk-devops-extend/src/main/java/com/splunk/splunkjenkins/PipelineRunSupport.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.cloudbees.workflow.rest.external.*; 4 | import com.splunk.splunkjenkins.model.LoggingJobExtractor; 5 | import hudson.Extension; 6 | import hudson.model.Result; 7 | import org.apache.commons.lang.StringUtils; 8 | import org.jenkinsci.plugins.workflow.flow.FlowExecution; 9 | import org.jenkinsci.plugins.workflow.graphanalysis.ForkScanner; 10 | import org.jenkinsci.plugins.workflow.graphanalysis.LabelledChunkFinder; 11 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Collection; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | @SuppressWarnings("unused") 20 | @Extension 21 | public class PipelineRunSupport extends LoggingJobExtractor { 22 | 23 | @Override 24 | public Map extract(WorkflowRun workflowRun, boolean jobCompleted) { 25 | Map info = new HashMap(); 26 | if (jobCompleted) { 27 | FlowExecution execution = workflowRun.getExecution(); 28 | if (execution != null) { 29 | WorkspaceChunkVisitor visitor = new WorkspaceChunkVisitor(workflowRun); 30 | //LabelledChunkFinder to find stages and parallel branches 31 | ForkScanner.visitSimpleChunks(execution.getCurrentHeads(), visitor, new LabelledChunkFinder()); 32 | Collection nodes = visitor.getStages(); 33 | Map execNodes = visitor.getWorkspaceNodes(); 34 | Map parallelNodeStages = visitor.getParallelNodes(); 35 | if (!nodes.isEmpty()) { 36 | List labeledChunks = new ArrayList(nodes.size()); 37 | for (StageNodeExt stageNodeExt : nodes) { 38 | Map stage = flowNodeToMap(stageNodeExt, execNodes); 39 | List> children = new ArrayList<>(); 40 | for (FlowNodeExt childNode : stageNodeExt.getStageFlowNodes()) { 41 | children.add(flowNodeToMap(childNode, execNodes)); 42 | } 43 | if (!children.isEmpty()) { 44 | stage.put("children", children); 45 | if (parallelNodeStages.containsKey(stageNodeExt.getId())) { 46 | stage.put("enclosing_stage", parallelNodeStages.get(stageNodeExt.getId())); 47 | } 48 | } 49 | labeledChunks.add(stage); 50 | } 51 | info.put("stages", labeledChunks); 52 | } 53 | } 54 | } 55 | return info; 56 | } 57 | 58 | /** 59 | * @param node FlowNodeExt 60 | * @return a map contains basic info 61 | */ 62 | private Map flowNodeToMap(FlowNodeExt node, Map execNodes) { 63 | Map result = new HashMap(); 64 | ErrorExt error = node.getError(); 65 | result.put("name", node.getName()); 66 | result.put("id", node.getId()); 67 | result.put("status", toResult(node.getStatus())); 68 | result.put("duration", node.getDurationMillis() / 1000f); 69 | result.put("pause_duration", node.getPauseDurationMillis() / 1000f); 70 | result.put("start_time", node.getStartTimeMillis() / 1000); 71 | if (error != null) { 72 | result.put("error", error.getMessage()); 73 | result.put("error_type", error.getType()); 74 | } 75 | result.put("arguments", node.getParameterDescription()); 76 | String execNodeName = node.getExecNode(); 77 | if (StringUtils.isEmpty(execNodeName)) { 78 | //lockup the workspace nodes 79 | execNodeName = execNodes.get(node.getId()); 80 | } 81 | result.put("exec_node", execNodeName); 82 | return result; 83 | } 84 | 85 | /** 86 | * @param status 87 | * @return String compatible with hudson.model.Result 88 | */ 89 | private String toResult(StatusExt status) { 90 | if (status == null) { 91 | return "UNKNOWN"; 92 | } 93 | switch (status) { 94 | case FAILED: 95 | return Result.FAILURE.toString(); 96 | case NOT_EXECUTED: 97 | return Result.NOT_BUILT.toString(); 98 | default: 99 | return status.toString(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /splunk-devops/src/test/resources/com/splunk/splunkjenkins/TestResultAdapterTest/jobs/testng_job1/workspace/testng-reporter-log-result.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/JacocoCoverageMetrics.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.Extension; 4 | import hudson.plugins.jacoco.JacocoBuildAction; 5 | import hudson.plugins.jacoco.model.Coverage; 6 | import hudson.plugins.jacoco.model.CoverageObject; 7 | import hudson.plugins.jacoco.report.ClassReport; 8 | import hudson.plugins.jacoco.report.CoverageReport; 9 | import hudson.plugins.jacoco.report.MethodReport; 10 | import hudson.plugins.jacoco.report.PackageReport; 11 | 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | import static com.splunk.splunkjenkins.Constants.COVERAGE_OVERALL_NAME; 18 | 19 | /** 20 | * CoverageMetric for JaCoCo 21 | */ 22 | @Extension(optional = true) 23 | public class JacocoCoverageMetrics extends CoverageMetricsAdapter { 24 | @Override 25 | public Map getMetrics(JacocoBuildAction coverageAction) { 26 | return extract(coverageAction); 27 | } 28 | 29 | private Map extract(CoverageObject coverageObject) { 30 | Map result = new HashMap<>(); 31 | addMetric(result, Metric.CLASS, coverageObject.getClassCoverage()); 32 | addMetric(result, Metric.METHOD, coverageObject.getMethodCoverage()); 33 | addMetric(result, Metric.BRANCH, coverageObject.getBranchCoverage()); 34 | addMetric(result, Metric.COMPLEXITY, coverageObject.getComplexityScore()); 35 | addMetric(result, Metric.INSTRUCTION, coverageObject.getInstructionCoverage()); 36 | addMetric(result, Metric.LINE, coverageObject.getLineCoverage()); 37 | return result; 38 | } 39 | 40 | private void addMetric(Map result, Metric metric, Coverage coverage) { 41 | if (coverage != null && coverage.getTotal() > 0) { 42 | result.put(metric, coverage.getPercentage()); 43 | } 44 | } 45 | 46 | private void appendDetail(CoverageDetail result, CoverageObject coverageObject) { 47 | appendDetail(result, Metric.CLASS, coverageObject.getClassCoverage()); 48 | appendDetail(result, Metric.METHOD, coverageObject.getMethodCoverage()); 49 | appendDetail(result, Metric.BRANCH, coverageObject.getBranchCoverage()); 50 | appendDetail(result, Metric.COMPLEXITY, coverageObject.getComplexityScore()); 51 | appendDetail(result, Metric.INSTRUCTION, coverageObject.getInstructionCoverage()); 52 | appendDetail(result, Metric.LINE, coverageObject.getLineCoverage()); 53 | } 54 | 55 | /** 56 | * add percentage, covered and total 57 | * 58 | * @param detail 59 | * @param reportMetric 60 | * @param coverage 61 | */ 62 | private void appendDetail(CoverageDetail detail, Metric reportMetric, Coverage coverage) { 63 | if (coverage != null && coverage.getTotal() > 0) { 64 | detail.add(reportMetric + PERCENTAGE_SUFFIX, coverage.getPercentage()); 65 | detail.add(reportMetric + TOTAL_SUFFIX, coverage.getTotal()); 66 | detail.add(reportMetric + COVERED_SUFFIX, coverage.getCovered()); 67 | } 68 | } 69 | 70 | @Override 71 | public List getReport(JacocoBuildAction coverageAction) { 72 | CoverageReport report = coverageAction.getResult(); 73 | List result = new ArrayList<>(); 74 | if (!report.hasChildren()) { 75 | return result; 76 | } 77 | CoverageDetail summary = new CoverageDetail(COVERAGE_OVERALL_NAME, CoverageLevel.PROJECT); 78 | result.add(summary); 79 | appendDetail(summary, coverageAction); 80 | Map packages = report.getChildren(); 81 | for (Map.Entry entry : packages.entrySet()) { 82 | CoverageDetail packageDetail = new CoverageDetail(entry.getKey(), CoverageLevel.PACKAGE); 83 | result.add(packageDetail); 84 | appendDetail(packageDetail, entry.getValue()); 85 | Map classReports = entry.getValue().getChildren(); 86 | for (Map.Entry classEntry : classReports.entrySet()) { 87 | CoverageDetail classDetail = new CoverageDetail(classEntry.getKey(), CoverageLevel.CLASS); 88 | result.add(classDetail); 89 | appendDetail(classDetail, classEntry.getValue()); 90 | Map methodReports = classEntry.getValue().getChildren(); 91 | for (Map.Entry methodEntry : methodReports.entrySet()) { 92 | CoverageDetail methodDetail = new CoverageDetail(methodEntry.getKey(), CoverageLevel.METHOD); 93 | result.add(methodDetail); 94 | appendDetail(methodDetail, methodEntry.getValue()); 95 | } 96 | } 97 | } 98 | return result; 99 | } 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/TestNGResultAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import hudson.Extension; 4 | import hudson.Util; 5 | import hudson.model.Run; 6 | import hudson.plugins.testng.TestNGTestResultBuildAction; 7 | import hudson.plugins.testng.results.ClassResult; 8 | import hudson.plugins.testng.results.MethodResult; 9 | import hudson.plugins.testng.results.MethodResultException; 10 | import hudson.plugins.testng.results.TestNGTestResult; 11 | import hudson.tasks.test.AbstractTestResultAction; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import static com.splunk.splunkjenkins.Constants.ERROR_MESSAGE_NA; 17 | 18 | @Extension(optional = true) 19 | public class TestNGResultAdapter extends AbstractTestResultAdapter { 20 | @Override 21 | public List getTestResult(TestNGTestResultBuildAction resultAction) { 22 | List testResults = resultAction.getResult().getTestList(); 23 | List caseResults = new ArrayList<>(); 24 | for (TestNGTestResult testResult : testResults) { 25 | for (ClassResult classResult : testResult.getClassList()) { 26 | for (MethodResult methodResult : classResult.getTestMethods()) { 27 | TestCaseResult testCaseResult = new TestCaseResult(); 28 | testCaseResult.setTestName(methodResult.getName()); 29 | testCaseResult.setUniqueName(methodResult.getSafeName()); 30 | testCaseResult.setDuration(methodResult.getDuration()); 31 | testCaseResult.setClassName(methodResult.getClassName()); 32 | testCaseResult.setGroupName(testResult.getName()); 33 | String status = Util.fixNull(methodResult.getStatus()).toLowerCase(); 34 | switch (status) { 35 | case "fail": 36 | MethodResultException exception = methodResult.getException(); 37 | if (exception != null) { 38 | if (exception.getMessage() != null) { 39 | testCaseResult.setErrorDetails(exception.getMessage()); 40 | } else { 41 | testCaseResult.setErrorDetails(exception.getExceptionName()); 42 | } 43 | } else { 44 | testCaseResult.setErrorDetails(ERROR_MESSAGE_NA); 45 | 46 | } 47 | testCaseResult.setErrorStackTrace(methodResult.getErrorStackTrace()); 48 | Run run = methodResult.getRun(); 49 | if (run != null) { 50 | int failedSince = getFailedSince(run, methodResult.getId()); 51 | testCaseResult.setFailedSince(failedSince); 52 | } 53 | testCaseResult.setStatus(TestStatus.FAILURE); 54 | break; 55 | case "skip": 56 | testCaseResult.setSkipped(true); 57 | testCaseResult.setStatus(TestStatus.SKIPPED); 58 | break; 59 | case "pass": 60 | testCaseResult.setStatus(TestStatus.PASSED); 61 | break; 62 | default: 63 | // empty status, marked as passed 64 | testCaseResult.setStatus(TestStatus.PASSED); 65 | } 66 | testCaseResult.setSkippedMessage(methodResult.getDescription()); 67 | testCaseResult.setStdout(methodResult.getReporterOutput()); 68 | caseResults.add(testCaseResult); 69 | } 70 | } 71 | } 72 | return caseResults; 73 | } 74 | 75 | /** 76 | * If this test failed, then return the build number 77 | * when this test started failing. 78 | * 79 | * @return the build number when this test started failing. 80 | */ 81 | private int getFailedSince(Run b, String id) { 82 | int i = 0; 83 | int buildNumber = 0; 84 | while (i++ < 20) { 85 | buildNumber = b.getNumber(); 86 | b = b.getPreviousBuild(); 87 | if (b == null) { 88 | return buildNumber; 89 | } 90 | AbstractTestResultAction r = b.getAction(targetType); 91 | if (r != null) { 92 | MethodResult result = (MethodResult) r.findCorrespondingResult(id); 93 | if (result == null || !"fail".equalsIgnoreCase(result.getStatus())) { 94 | return buildNumber; 95 | } 96 | } else { 97 | return buildNumber; 98 | } 99 | } 100 | return buildNumber; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/model/CucumberTestResultAdapter.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins.model; 2 | 3 | import gherkin.formatter.model.Result; 4 | import gherkin.formatter.model.Step; 5 | import hudson.Extension; 6 | import hudson.tasks.test.TestObject; 7 | import hudson.tasks.test.TestResult; 8 | import org.apache.commons.lang.reflect.FieldUtils; 9 | import org.jenkinsci.plugins.cucumber.jsontestsupport.*; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | @Extension(optional = true) 16 | public class CucumberTestResultAdapter extends AbstractTestResultAdapter { 17 | @Override 18 | public List getTestResult(CucumberTestResultAction resultAction) { 19 | List caseResults = new ArrayList<>(); 20 | Collection featureResults = resultAction.getResult().getChildren(); 21 | //prefix is cucumber/ 22 | String prefix = resultAction.getResult().getName() + "/"; 23 | for (FeatureResult featureResult : featureResults) { 24 | for (ScenarioResult scenarioResult : featureResult.getChildren()) { 25 | String className = scenarioResult.getId(); 26 | if (className.startsWith(prefix)) { 27 | className = className.substring(prefix.length()); 28 | } 29 | for (BeforeAfterResult beforeAfterResult : scenarioResult.getBeforeResults()) { 30 | TestCaseResult testCaseResult = convert(beforeAfterResult, className); 31 | caseResults.add(testCaseResult); 32 | } 33 | for (StepResult stepResult : scenarioResult.getStepResults()) { 34 | TestCaseResult testCaseResult = convert(stepResult, className); 35 | testCaseResult.setTestName(getStepName(stepResult)); 36 | caseResults.add(testCaseResult); 37 | } 38 | for (BeforeAfterResult afterResult : scenarioResult.getAfterResults()) { 39 | TestCaseResult testCaseResult = convert(afterResult, className); 40 | caseResults.add(testCaseResult); 41 | } 42 | } 43 | } 44 | return caseResults; 45 | } 46 | 47 | /** 48 | * @param testResult bdd test result 49 | * @param className bdd test scenario name 50 | * @return 51 | */ 52 | private TestCaseResult convert(TestResult testResult, String className) { 53 | TestCaseResult testCaseResult = new TestCaseResult(); 54 | testCaseResult.setTestName(testResult.getName()); 55 | testCaseResult.setClassName(className); 56 | testCaseResult.setSkipped(testResult.getSkipCount() > 0); 57 | testCaseResult.setDuration(testResult.getDuration()); 58 | testCaseResult.setUniqueName(testResult.getId()); 59 | if (testResult.getSkipCount() > 0) { 60 | testCaseResult.setStatus(TestStatus.SKIPPED); 61 | } else if (testResult.getFailCount() > 0) { 62 | testCaseResult.setStatus(TestStatus.FAILURE); 63 | } else { 64 | testCaseResult.setStatus(TestStatus.PASSED); 65 | } 66 | testCaseResult.setFailedSince(testResult.getFailedSince()); 67 | if (testCaseResult.getStatus() == TestStatus.FAILURE) { 68 | updateErrorDetails(testResult, testCaseResult); 69 | } 70 | TestObject parent = testResult.getParent(); 71 | if (parent != null) { 72 | testCaseResult.setGroupName(parent.getName()); 73 | } 74 | return testCaseResult; 75 | } 76 | 77 | private void updateErrorDetails(TestResult testResult, TestCaseResult testCaseResult) { 78 | try { 79 | Result result = (Result) FieldUtils.readField(testResult, "result", true); 80 | String errorMessage = result.getErrorMessage(); 81 | if (errorMessage != null) { 82 | //errorMessage is stack trace 83 | int idx = errorMessage.indexOf(": "); 84 | idx = idx > 0 ? idx : errorMessage.indexOf("\n"); 85 | if (idx == -1) { //errorMessage is not an exception 86 | idx = Math.min(80, errorMessage.length()); 87 | } 88 | testCaseResult.setErrorDetails(errorMessage.substring(0, idx)); 89 | testCaseResult.setErrorStackTrace(errorMessage); 90 | } 91 | } catch (IllegalArgumentException e) { 92 | //just ignore, api changed 93 | } catch (ReflectiveOperationException e) { 94 | } 95 | } 96 | 97 | private String getStepName(StepResult stepResult) { 98 | String stepName = ""; 99 | try { 100 | Step step = (Step) FieldUtils.readField(stepResult, "step", true); 101 | stepName = step.getKeyword() + " " + step.getName(); 102 | } catch (IllegalArgumentException e) { 103 | //just ignore, api changed 104 | } catch (ReflectiveOperationException e) { 105 | } 106 | return stepName; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /splunk-devops/src/main/resources/junit.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /splunk-devops-extend/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.splunk.splunkins 7 | pom 8 | 1.7.5-SNAPSHOT 9 | 10 | 11 | splunk-devops-extend 12 | hpi 13 | 14 | Splunk Plugin Extension 15 | Support Extracting Pipeline Stage Node 16 | https://wiki.jenkins-ci.org/display/JENKINS/Splunk+Plugin+for+Pipeline+Job+Support 17 | 18 | 19 | MIT License 20 | http://opensource.org/licenses/MIT 21 | 22 | 23 | 24 | 2.89.1 25 | 26 | 27 | 28 | fengxx 29 | Ted Xiao 30 | xiao.xj@outlook.com 31 | 32 | 33 | 34 | 35 | 36 | ${project.groupId} 37 | splunk-devops 38 | ${project.version} 39 | 40 | 41 | org.jenkins-ci.plugins.pipeline-stage-view 42 | pipeline-rest-api 43 | 2.8 44 | 45 | 46 | org.jenkins-ci.main 47 | jenkins-test-harness 48 | test 49 | 50 | 51 | ${project.groupId} 52 | splunk-devops 53 | ${project.version} 54 | test-jar 55 | test 56 | 57 | 58 | org.jenkins-ci.plugins.workflow 59 | workflow-durable-task-step 60 | 2.9 61 | test 62 | 63 | 64 | org.jenkins-ci.plugins.workflow 65 | workflow-api 66 | 2.27 67 | 68 | 69 | org.jenkins-ci.plugins.workflow 70 | workflow-job 71 | 2.21 72 | 73 | 74 | org.jenkins-ci.plugins.workflow 75 | workflow-step-api 76 | 2.13 77 | 78 | 79 | org.jenkins-ci.plugins.workflow 80 | workflow-cps 81 | 2.53 82 | 83 | 84 | org.jenkins-ci.plugins.workflow 85 | workflow-support 86 | 2.17 87 | test 88 | 89 | 90 | org.jenkins-ci.plugins.workflow 91 | workflow-basic-steps 92 | 2.4 93 | test 94 | 95 | 96 | org.jenkins-ci.plugins.workflow 97 | workflow-multibranch 98 | 2.19 99 | test 100 | 101 | 102 | org.jenkins-ci.plugins 103 | structs 104 | 1.14 105 | 106 | 107 | org.jenkins-ci.plugins 108 | script-security 109 | 1.42 110 | 111 | 112 | org.jenkins-ci.plugins 113 | scm-api 114 | 2.2.6 115 | 116 | 117 | org.jenkins-ci.plugins 118 | junit 119 | 1.18 120 | test 121 | 122 | 123 | 124 | org.jenkins-ci.ui 125 | jquery-detached 126 | 1.2.1 127 | test 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /splunk-devops/src/main/java/com/splunk/splunkjenkins/HealthMonitor.java: -------------------------------------------------------------------------------- 1 | package com.splunk.splunkjenkins; 2 | 3 | import com.splunk.splunkjenkins.model.EventType; 4 | import com.splunk.splunkjenkins.utils.SplunkLogService; 5 | import hudson.Extension; 6 | import hudson.model.*; 7 | import hudson.model.Queue; 8 | import jenkins.model.Jenkins; 9 | 10 | import java.io.IOException; 11 | import java.lang.management.ManagementFactory; 12 | import java.lang.management.MemoryPoolMXBean; 13 | import java.lang.management.MemoryUsage; 14 | import java.util.*; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | import static com.splunk.splunkjenkins.model.EventType.QUEUE_INFO; 18 | import static com.splunk.splunkjenkins.model.EventType.SLAVE_INFO; 19 | import static com.splunk.splunkjenkins.Constants.NODE_NAME; 20 | import static com.splunk.splunkjenkins.Constants.SLAVE_TAG_NAME; 21 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getMasterStats; 22 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getRunningJob; 23 | import static com.splunk.splunkjenkins.utils.LogEventHelper.getSlaveStats; 24 | 25 | @Extension 26 | public class HealthMonitor extends AsyncPeriodicWork { 27 | //make sure no less than 2 minutes, default is 8 minutes 28 | private long slaveUpdatePeriod = TimeUnit.MINUTES.toMillis(Math.max(2, Long.getLong("com.splunk.splunkjenkins.slaveMonitorMinutes", 8))); 29 | private long period = TimeUnit.SECONDS.toMillis(Math.max(20, Long.getLong("com.splunk.splunkjenkins.queueMonitorSeconds", 45))); 30 | 31 | private Set slaveNames = new HashSet<>(); 32 | //use protected to allow tweak it in testcase 33 | protected long lastAccessTime = System.currentTimeMillis(); 34 | 35 | public HealthMonitor() { 36 | super("Splunk data monitor"); 37 | } 38 | 39 | @Override 40 | protected void execute(TaskListener listener) throws IOException, InterruptedException { 41 | if (!SplunkJenkinsInstallation.get().isEnabled()) { 42 | return; 43 | } 44 | sendPendingQueue(); 45 | if (System.currentTimeMillis() - lastAccessTime < slaveUpdatePeriod) { 46 | return; 47 | } 48 | lastAccessTime = System.currentTimeMillis(); 49 | sendNodeUpdate(); 50 | listener.getLogger().println("execute sendNodeUpdate"); 51 | } 52 | 53 | private void sendNodeUpdate() { 54 | Map> slaveStats = getSlaveStats(); 55 | Set aliveSlaves = slaveStats.keySet(); 56 | //send event one by one instead of list to aid search 57 | SplunkLogService.getInstance().sendBatch(slaveStats.values(), SLAVE_INFO); 58 | List removedSlavs = new ArrayList<>(); 59 | for (String slaveName : slaveNames) { 60 | if (!aliveSlaves.contains(slaveName)) { 61 | Map event = new HashMap(); 62 | event.put(Constants.TAG, SLAVE_TAG_NAME); 63 | event.put(NODE_NAME, slaveName); 64 | event.put("status", "removed"); 65 | removedSlavs.add(event); 66 | } 67 | } 68 | SplunkLogService.getInstance().sendBatch(removedSlavs, SLAVE_INFO); 69 | SplunkLogService.getInstance().sendBatch(getRunningJob(), QUEUE_INFO); 70 | //replace slave names, at one time should only one thread is running, so modify slaveNames is safe without lock 71 | slaveNames = aliveSlaves; 72 | //update master stats 73 | Map masterEvent = getMasterStats(); 74 | masterEvent.put("item", name); 75 | masterEvent.put(Constants.TAG, Constants.QUEUE_TAG_NAME); 76 | SplunkLogService.getInstance().send(masterEvent, QUEUE_INFO); 77 | //send memory details 78 | List memoryUsages = new ArrayList(); 79 | for (MemoryPoolMXBean memoryPoolMXBean : ManagementFactory.getMemoryPoolMXBeans()) { 80 | Map memoryPoolUsage = new HashMap(); 81 | MemoryUsage usageDetail = memoryPoolMXBean.getUsage(); 82 | memoryPoolUsage.put(Constants.TAG, "jvm_memory"); 83 | memoryPoolUsage.put("memory_pool", memoryPoolMXBean.getName()); 84 | memoryPoolUsage.put("init_size", usageDetail.getInit() >> 20); 85 | memoryPoolUsage.put("max_size", usageDetail.getMax() >> 20); 86 | memoryPoolUsage.put("committed_size", usageDetail.getCommitted() >> 20); 87 | memoryPoolUsage.put("used_size", usageDetail.getUsed() >> 20); 88 | memoryUsages.add(memoryPoolUsage); 89 | } 90 | SplunkLogService.getInstance().sendBatch(memoryUsages, EventType.QUEUE_INFO); 91 | } 92 | 93 | private void sendPendingQueue() { 94 | //send queue items 95 | Queue.Item[] items = Jenkins.getInstance().getQueue().getItems(); 96 | List queue = new ArrayList<>(items.length); 97 | for (int i = 0; i < items.length; i++) { 98 | Queue.Item item = items[i]; 99 | Map queueItem = new HashMap(); 100 | queueItem.put("queue_id", item.getId()); 101 | queueItem.put("queue_time", (System.currentTimeMillis() - item.getInQueueSince()) / 1000f); 102 | queueItem.put("stuck", item.isStuck()); 103 | queueItem.put("block_reason", item.getWhy()); 104 | queueItem.put("concurrent_build", item.task.isConcurrentBuild()); 105 | queueItem.put(Constants.TAG, Constants.QUEUE_WAITING_ITEM_NAME); 106 | String jobName; 107 | if (item.task instanceof Job) { 108 | jobName = ((Job) item.task).getFullName(); 109 | } else { 110 | jobName = item.task.getUrl(); 111 | } 112 | queueItem.put("task", jobName); 113 | queue.add(queueItem); 114 | } 115 | SplunkLogService.getInstance().sendBatch(queue, QUEUE_INFO); 116 | } 117 | 118 | @Override 119 | public long getRecurrencePeriod() { 120 | return period; 121 | } 122 | } 123 | --------------------------------------------------------------------------------