Logging

On AWS Lambda for Java, by default, whichever you print with System.{out,err}.println is written into CloudWatch Logs, provided its execution role allows it. As such, you can use the AWS CloudWatch Logs console, or consider using a tool like smoketail to do it.

AWS wrote a particular appender for usage with log4j. Its source it kept here. If you notice, it interacts with the underlying Lambda Runtime (see "Under the Hood"), thus changing its behaviour:

package com.amazonaws.services.lambda.runtime.log4j;

public class LambdaAppender extends AppenderSkeleton {
    LambdaLogger logger = LambdaRuntime.getLogger(); // #1

    public LambdaAppender() {
        super();
        LambdaRuntimeInternal.setUseLog4jAppender(true); // #2
    }

    @Override
    protected void append(LoggingEvent event) {
        if(this.layout == null) {
            logger.log(event.getLevel() + " " + event.getMessage());
            return;
        }
        logger.log(this.layout.format(event));
        //prints the Throwable from the log
        if(layout.ignoresThrowable()) {
            StringBuilder traceString = new StringBuilder();
            String[] s = event.getThrowableStrRep();
            if (s != null) {
                int len = s.length;
                for(int i = 0; i < len; i++) {
                    traceString.append(s[i]);
                    traceString.append(Layout.LINE_SEP);
                }
            }
            logger.log(traceString.toString()); // #3
        }
    }
}

The three lines marked above show how its done. Once you grasp how simple it is, adapting an existing framework like log4j (or logback) becomes a matter of properly redirecting its calls to LambdaLogger, just like LambdaAppender did above.

However, you must ensure to NOT buffer/making asynchronous the log output. Once results are sent back to AWS Lambda, any background work (like Threads) will be killed. Note this also applies for any critical code related to Java's Shutdown Hooks.