Skip to main content

Version: 23.10

Debugging Guide

In general, debugging Transact Functions can be achieved by a few different techniques, each with their own different capabilities and advantages.

  • Logging
  • Unit Tests
  • Debugger IDEs

Here are some of the relative advantages and disadvantages of each technique.

MethodAdvantagesDisadvantages
Logging
  • You can use logging inside and outside of TM
  • Logging is easy to implement
  • A Logger is injected into every form function by default
  • You can quickly add and remove logging code in the TM console
  • The logger provides rich object output formatting
  • Useful in production to assist problem diagnosis
  • You need to take care not to log sensitive information
  • You can potentially flood the logs with too much information
Unit tests
  • Tests can be executed inside the TM console on demand
  • Tests can be executed outside of TM by the SDK
  • Tests can be automated
  • Tests can cover many different use cases
  • Tests can use mocking features to simulate live environments
  • Tests can include logging
  • Unit testing can leverage code coverage tools
  • Unit testing is best practice for any project
  • Unit tests are an excellent mechanism to protect against regressions
  • You need to spend some time writing test code
Debugger IDEs
  • Allow breakpoints and code stepping
  • Allow call stack and variable inspection
  • Provide a very rich IDE experience
  • Increase productivity in large projects
  • Can only run outside of TM in the SDK environment
  • Need to be initiated by running a Junit test

Logging

The Journey Manager server executes Groovy services inside a Groovy container and it is not possible to remotely attach a debugger to the executing container. Inside TM, logging is your only option to see what is happening at runtime.

The Logger object injected into form functions in TM provides excellent object dump capabilities. For example, the output below results from a single call to the logger to output the param FuncParam object passed to the form function's invoke method.

public class GetExchangeRate {
public Logger logger
FuncResult invoke(FuncParam param) {
logger.info param

Logger output from the highlighted logger.info call above is:

07:45:58,064 INFO  com.avoka.tm.func.FuncParam@6cf4a83e[
trigger=Form Function
appDoc=[#document: null]
params={from=AUD, to=USD}
request=SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ HttpServletRequestImpl [ POST /web-plugin/servlet/FormDynamicDataServlet ]]]
svcDef=com.avoka.tm.vo.SvcDef@5df492ea[
id=450
name=Get Exchange Rate
versionNumber=0
version=0.1.0
orgId=3
clientCode=billfrost
type=Fluent Function
description=TODO...
isCurrentVersion=true
isJobTemplate=false
isUnitTestEnabled=true
className=com.avoka.fc.core.service.fluent.FluentFunctionService
createdAt=Thu Jan 25 09:09:38 AEDT 2018
createdBy=bill
lastModifiedAt=Mon Jan 29 07:45:29 AEDT 2018
lastModifiedBy=bill
svcConn=com.avoka.tm.vo.SvcConn@14087432[
id=27
name=Exchange Rate Connection
orgId=3
clientCode=billfrost
endpoint=http://api.fixer.io/latest
type=HTTP Endpoint
username=
password=
]
paramsMap={executionTimeout=0, groovyDebugLogging=false, groovyLoggingEnabled=true}
]
txn=com.avoka.tm.vo.Txn@efd2e26[
id=3473
orgId=3
clientCode=billfrost
orgName=Bill Frost Org
deliveryStatus=Not Ready
formId=747
formCode=exchangerate
formName=Exchange Rate
formStatus=Opened
groupNames=[]
spaceId=6
spaceName=Web Plug-in
timeCreated=Mon Jan 29 07:45:41 AEDT 2018
timeUserLastModified=Mon Jan 29 07:45:42 AEDT 2018
dataDeleted=false
submitKey=f4a96743adeb807f9d4f51384dcb1a75
trackingCode=W7DWFYW
userSaved=false
formVersionId=767
formVersionNumber=1.0-develop
formUrl=http://localhost:9080/web-plugin/servlet/SmartForm.html?submitKey=f4a96743adeb807f9d4f51384dcb1a75
receiptUrl=http://localhost:9080/web-plugin/servlet/FormReceipt.pdf?submitKey=f4a96743adeb807f9d4f51384dcb1a75
formDataMap={}
propertyMap={}
milestones=[formload]
formXml=
]
]

Logging in Unit Tests

Unit tests support logging while running inside TM, and while running under the SDK in your IDE. You can view logger output in the TM console or in your IDE's console output window.

Logging in Production

Anybody with sufficient credentials will be able to see logged messages in production even if they do not have an entitlement to access the logged information by other means.

note

Logging is simple and convenient, so take care in production environments to ensure that no sensitive or personally identifiable information is logged.

Unit Tests

Unit testing in JM and the Journey SDK is provided by JUnit. Unit testing is a standard part of any form function scaffolded by the SDK.

Unit testing is best practice and provides advantages that easily outweigh the relatively small cost of their development.

To take advantage of the features of a debugger, you must execute your function under test from a JUnit test class.

Mocking

One of the common techniques that accompanies unit testing is mocking and mocking frameworks.

Mocks are objects you create that appear to the function under test to be a real object, whereas it is actually just a stub that you manipulate in your unit test code to behave the way you want.

The Journey SDK provides several classes to support mocking in unit tests. For more information, see the Unit Testing Guide.

Debugger IDEs

The Journey SDK provides a local execution environment that supports debugging JUnit tests outside of Journey Manager. This method offers a richer development experience through access to debugging techniques such as setting breakpoints and inspecting the call stack or the contents of variables while paused.

Debugging form functions with a debugger is always done via JUnit tests. Using JUnit has some advantages over logging.

  • You can have many different JUnit tests to exercise different conditions.
  • You can use mocking to simulate a live environment.
  • JUnit tests can be automated by SDK Ant tasks.
  • Junit tests can be run in the TM console.
  • JUnit tests can be run in your IDE, leveraging rich IDE debugging features.

To use the debugger you must always execute a Groovy unit test. It will in turn make a call to the invoke method of the form function it is exercising. You can set breakpoints wherever you want in the test or in the function code, but you always need to start by running the Groovy unit test code as a JUnit test first.

Debugging in the IDE is as simple as setting a breakpoint where you want, right-clicking on a Groovy unit test and selecting Debug from the context menu as shown below using IntelliJ.

alt-text

In IntelliJ you can also click the Debug icon from the toolbar as shown below.

alt-text

When the breakpoint is hit, you can view frames from the call stack, and can hover over a variable and inspect its content by clicking on it like this.

alt-text