6

I am trying to write a shared libray which combines of global variables and shared functions to perform automated task of build and deployment for our project

The project layout as below:

enter image description here

The project has two major parts:

  1. Global shared variables which are placed in vars folder

  2. Supporting groovy scripts to abstract logics which in turn will be called in the global variable.

enter image description here

Inside the groovy class, I am using println to log debugging information

enter image description here

But it never got printed out when it is invoked through jenkins pipeline job

enter image description here

The log console of jenkins job as below:

enter image description here

Can someone show me how to propage logs from groovy class to jenkins job console as I can see only log from println in the global shared script is shown in log console.

Joey Trang
  • 1,105
  • 2
  • 23
  • 44

4 Answers4

7

I just found a way to do it by calling println step that is available in the jenkins job

Basically I create a wrapper function as below in Groovy class PhoenixEurekaService:

enter image description here

The steps is actually the jenkins job environment passed into Groovy class via constructor. By this way we can call any steps available in jenkins job in Groovy class.

enter image description here

In global groovy script PhoenixLib.groovy

enter image description here

I am not sure is there other way to do that...

Joey Trang
  • 1,105
  • 2
  • 23
  • 44
  • Where are you calling log() and how the heck are you passing steps into your PhoenixEurekaService constructor from your Jenkinsfile? – Andrew Gray Mar 05 '18 at 03:23
  • You need to pass 'this' as an argument from the pipeline script. I uses a groovy class that I construct passing 'this' as a parameter from the global script in the /var directory. In the constructor I save it to the member variable named 'this'. See https://jenkins.io/doc/book/pipeline/shared-libraries/ – cmac Mar 25 '18 at 20:42
  • 1
    Thank you. Very useful information. I am still partly stuck with an underlying java program, used by the library, which is logging by f.e. log4j. Logs written to stdout do not appear in the jenkins log. Somehow this -this- object needs to be passed to the log4j framework. Anyone already got this work? – Mike Apr 13 '18 at 09:05
  • I'm doing much the same. I feel like there must be a way to tie into the general jenkins logging system in the same manner a plugin works so I could use log4j or some other framework. However, that complexity may not buy me much. A simple base class with steps member could be enough. – Peter Kahn Jul 18 '19 at 17:02
  • BTW have you played with https://github.com/jenkinsci/JenkinsPipelineUnit? I use it for running unit tests on my shared lib with mocking. It feels a little complex but I can have a build with coverage to test the lib. Therefore, I can commit with confidence or some degree of it. – Peter Kahn Jul 18 '19 at 17:04
  • this is not clear in which library you got the function println – White Sep 30 '21 at 12:40
3

All the commands/DSL e.g: println, sh, bat, checkout etc can't be accessed from shared library. ref: https://jenkins.io/doc/book/pipeline/shared-libraries/.

You can access steps by passing them to shared library.

//your library
package org.foo
class Utilities implements Serializable {
  def steps
  Utilities(steps) {this.steps = steps}
  def mvn(args) {
    steps.println "Hello world"
    steps.echo "Hello echo"
    //steps.sh "${steps.tool 'Maven'}/bin/mvn -o ${args}"
  }
} 

jenkinsfile

@Library('utils') import org.foo.Utilities
def utils = new Utilities(this)
node {
  utils.mvn '!!! so this how println can be worked out or any other step!!'
}
old-monk
  • 799
  • 8
  • 20
0

I am not a 100% sure if this what you are looking for, but printing things in a shared library can be achieved by passing steps and using echo. See Accessing steps in https://jenkins.io/doc/book/pipeline/shared-libraries/

Steve
  • 71
  • 3
0

This answer addresses those who need to log something from deep in the call stack. It might be cumbersome to pass pipeline "steps" object all the way in the stack of the shared library especially when the call hierarchy gets complex. One might therefore create a helper class with a static Closure that holds some logic to print to the console. For example:

class JenkinsUtils {

    static Closure<Void> log = { throw new RuntimeException("Logger not configured") }

}

In the steps groovy, this needs to be initialized (ideally in a NonCPS block). For example your Jenkinsfile (or var file):

@NonCPS
def setupLogging() {
  JenkinsUtils.log = { String msg-> println msg }
}

def call() {
  ...
  setupLogging()
  ...
}

And then, from any arbitrary shared library class one can call print to console simply like:

class RestClient {

  void doStuff() {
    JenkinsUtils.log("...")
  }
  
}

I know this is still hacky for a workaround, although I could not find any better working solution even though I spent quite some time researching.

Posted this also as a gist to my github profile

ThomasMX
  • 1,643
  • 2
  • 19
  • 35