Log messages are not showing up in groovy jenkins script - jenkins

I'm in need to extend my jenkins scripts with logging functionality and tried to use java.util.logging for this purpose. The following snippet shows what I already did.
import java.util.logging.*
#NonCPS
def tryLogging() {
println("Start")
Logger logger = Logger.getLogger("Test")
logger.setLevel(Level.INFO);
logger.setUseParentHandlers(false);
ConsoleHandler handler = new java.util.logging.ConsoleHandler()
handler.setFormatter(new SimpleFormatter())
logger.addHandler(handler)
logger.info("Hello")
logger.severe("Severe")
println("End")
}
tryLogging()
My console log now says the following:
[Pipeline] Start of Pipeline
[Pipeline] echo
Start
[Pipeline] echo
End
There is really no visible log message and I don't know, what I'm doing wrong. Can anyone here explain me how to make the console log visible? I'm also unsure if I have to use this #NonCPS here?
[Pipeline] End of Pipeline
Finished: SUCCESS

ConsoleHandler prints to System.err. Modify your script to use
System.err.println("Start") and see if 'Start' still shows up in the console. If it doesn't then the problem is the ConsoleHandler is writing to a stream you can't see.
Another thing to change is that you'll want to ensure your named logger can't be garbage collected. Depending the Java version you are using the logger can be garbage collected and you can lose your attached handler.
I'm also unsure if I have to use this #NonCPS here?
What is #NonCPS annotation in Jenkins pipeline script has information that you might find helpful.

Related

Jenkins console script different results

I am trying to get last successful build on multibranch pipeline job, and only what I came to is this
def str = Jenkins.instance.getAllItems() .findAll{ it instanceof Job }.collect{ it.getLastSuccessfulBuild() }.findAll{ it } .sort{ it.timestamp }.grep(~/iOS.*/).last().toString()
println str.substring(str.lastIndexOf('/') + 1).replace('%2F', '_').replace(' #', '_')
but unfortunately, this only works in script console of Jenkins, and throwing different results in pipeline, any guesses what could be wrong?
Jenkins version 2.176.1
I expect the output of:
feature_INC-777_77
But getting:
java.util.GregorianCalendar[time=1566913952011,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=35,WEEK_OF_MONTH=5,DAY_OF_MONTH=27,DAY_OF_YEAR=239,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=52,SECOND=32,MILLISECOND=11,ZONE_OFFSET=10800000,DST_OFFSET=0]
For pipeline like:
import jenkins.model.*
import hudson.model.*
import jenkins.*
import hudson.*
def str = Jenkins.instance.getAllItems().findAll{ it instanceof Job }.collect{ it.getLastSuccessfulBuild() }.findAll{ it }.sort{it.timestamp}
println str
Can someone help with this, please?
ah this beautiful groovy + Jenkins combo...
put your statement into a method and add annotation on top #NonCPS
While I will be in trouble to get a clear full explanation, in short - jenkins push all the code in your scripted pipeline via super-complicated (as for me) set of CPS transforms - https://github.com/cloudbees/groovy-cps/ , which may or may not convert groovy API properly. Rule of thumb - when using closures - use #NonCPS annotation, otherwise you will have a ton of weird errors that are hard to debug.
more info:
https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches
https://github.com/jenkinsci/workflow-cps-plugin
What is the effect of #NonCPS in a Jenkins pipeline script

Is there a Jenkins env var for Replay?

Does Jenkins provide a variable when replay is ran? If so what is that? I see in the log that is writes Replayed but I am not looking to scrape the console output.
You can use 'cause' of which has triggered the job, in rawBuild.
def replayClassName = "org.jenkinsci.plugins.workflow.cps.replay.ReplayCause​"
def isReplay = currentBuild.rawBuild.getCauses().any{ cause -> cause.toString().contains(replayClassName) }
*refered from
How to know inside jenkinsfile / script that current build is a replay?

How add Reporter.log() to log on Jenkins?

How can I add Reporter.log() on Jenkins log?
I write my test in java and used TestNG.
I try import:
import org.testng.Reporter;
next write method:
Reporter.log("Click on button next");
click(btnNext);
return this;
}
and write test:
public void shouldPageChangeAfterClick(){
mainPage
.launch()
.clickOnBtnNextPage()
.assertThatPageIsCorrect();
}
Next I run test on Jenkins from pom.xml, test is failed, but I don't see Reporter.log() in log on Jenkins.
What should I do to display Reporte.log() on Jenkins?
Reporter.log() method is to log the passed string to the HTML report. It will not print in any console or log file. You have to use different logger api to get the same in Jenkins console. Log4j will be helpful in this case.

How to run groovy script to read build cause?

I am writing a first groovy script in the Jenkins, have an upstream job A which calls job B.
Being in job B I need to read GERRIT_CHANGE_NUMBER which triggered the job A.
In below e.g, how to get 28331 in the downstream job B?, its printed in the job B's console as below:
Started by upstream project some_up_project build number 100
originally caused by:
Triggered by Gerrit: https://gerrit-server.com/28331
I looked at this SO answer, but not sure how to do this in jenkins.
In job B, I did Add build step to add Execute system Groovy script section, then chose Groovy command in its dropdown, and in the Groovy Script area, added below for testing purpose, it gives error as unable to resolve class Run.cause ..., tried many other ways too and nothing worked.
import hudson.model.Run
for (cause in Run.getCauses()) {
if (cause instanceof Run.Cause.UserIdCause) {
println cause.getUserName()
}
}
there is no such class Run.Cause
start from something that works: hudson.model.Run
search for the documentation: hudson.model.Run.getCauses()
the method returns: List<Cause>
so, import this class into your code and use it:
import hudson.model.Cause
import hudson.model.Run
for (cause in Run.getCauses()) {
if (cause instanceof Cause.UserIdCause) {
println cause.getUserName()
}
}
Note: I have not tested the code. I just gave you an idea how to resolve an error.

Get console Logger (or TaskListener) from Pipeline script method

If I have a Pipeline script method in Pipeline script (Jenkinsfile), my Global Pipeline Library's vars/ or in a src/ class, how can obtain the OutputStream for the console log? I want to write directly to the console log.
I know I can echo or println, but for this purpose I need to write without the extra output that yields. I also need to be able to pass the OutputStream to something else.
I know I can call TaskListener.getLogger() if I can get the TaskListener (really hudson.util.StreamTaskListener) instance, but how?
I tried:
I've looked into manager.listener.logger (from the groovy postbuild plugin) and in the early-build context I'm calling from it doesn't yield an OutputStream that writes to the job's Console Log.
echo "listener is a ${manager.listener} - ${manager.listener.getClass().getName()} from ${manager} and has a ${manager.listener.logger} of class ${manager.listener.logger.getClass().getName()}"
prints
listener is a hudson.util.LogTaskListener#420c55c4 - hudson.util.LogTaskListener from org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildRecorder$BadgeManager#58ac0c55 and has a java.io.PrintStream#715b9f99 of class java.io.PrintStream
I know you can get it from a StepContext via context.get(TaskListener.class) but I'm not in a Step, I'm in a CpsScript (i.e. WorkflowScript i.e. Jenkinsfile).
Finding it from a CpsFlowExecution obtained from the DSL instance registered as the steps script-property, but I couldn't work out how to discover the TaskListener that's passed to it when it's created
How is it this hard? What am I missing? There's so much indirect magic I find it incredibly hard to navigate the system.
BTW, I'm aware direct access is blocked by Script Security, but I can create #Whitelisted methods, and anything in a global library's vars/ is always whitelisted anyway.
You can access the build object from the Jenkins root object:
def listener = Jenkins.get()
.getItemByFullName(env.JOB_NAME)
.getBuildByNumber(Integer.parseInt(env.BUILD_NUMBER))
.getListener()
def logger = listener.getLogger() as PrintStream
logger.println("Listener: ${listener} Logger: ${logger}")
Result:
Listener: CloseableTaskListener[org.jenkinsci.plugins.workflow.log.BufferedBuildListener#6e9e6a16 / org.jenkinsci.plugins.workflow.log.BufferedBuildListener#6e9e6a16] Logger: java.io.PrintStream#423efc01
After banging my head against this problem for a couple days I think I have a solution:
CpsThreadGroup.current().execution.owner.listener
It's ugly, and I don't know if it's correct or if there's a better way, but seems to work.

Resources