Logging using Log4j

FunctionGraph service supports Java function logging using Log4j and Slf4j.

Note

As all FunctionGraph instances write to the same log, it can be difficult to distinguish logs of different requests. Writing to stdout or stderr will need to log the requestId of the request obtained from the Context.

The provided RunTimeLogger will add the requestId to the log output (see: see: Logging using RunTimeLogger).

Using a logging framework the user is responsible for adding the requestId to the log output. This can be achieved by using ThreadContext object.

This section describes how to use functions and log4j to implement log printing.

/*
 * Copyright (c) 2025 T-Systems International GmbH.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.opentelekomcloud.samples;

import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.util.LoaderUtil;


import com.google.gson.JsonObject;
import com.opentelekomcloud.services.runtime.Context;
import com.opentelekomcloud.services.runtime.RuntimeLogger;

import lombok.extern.slf4j.Slf4j;

/*
 * 
 * Sample on how to use Slf4j logging
 * 
 * FunctionGraph configuration:
 * Handler name: com.opentelekomcloud.samples.FGLoggingSLF4j.handleRequest
 * 
 * Initialization: ON
 * Function Initializer: com.opentelekomcloud.samples.FGLoggingSLF4j.initializer
 * 
 * Class Isolation: ON
 * 
 * Environment Variables
 * - LOG_LEVEL = DEBUG
 * 
 */
@Slf4j
public class FGLoggingSLF4j {
  /**
   * Setup logging in initializer
   */
  public void initializer(Context context) {
    RuntimeLogger rlog = context.getLogger();
    rlog.log("Start initializing...");
    try {
      // put requestId into ThreadContext
      
      ThreadContext.put("requestid", context.getRequestID());
      // Initialize Log4J
      try {
        Configurator.reconfigure(
            Objects.requireNonNull(LoaderUtil.getThreadContextClassLoader().getResource("log4j2.xml")).toURI());
      } catch (URISyntaxException e) {
        rlog.error("An error occurred while configuring Log4J:" + e.getMessage());
        throw new RuntimeException(e);
      }

      // set log level
      String log_level = context.getUserData("LOG_LEVEL");

      List<String> allowed = Arrays.asList("DEBUG", "INFO", "WARN", "ERROR");
      if (!allowed.contains(log_level)) {
        log_level = "DEBUG";
      }

      Level level = Level.getLevel(log_level);
      Configurator.setRootLevel(level);

    } finally {
      // remove requestId from ThreadContext     
      ThreadContext.remove("requestid");
    }

    rlog.log("Finished initializing...");
  }

  /**
   * FunctionGraph Handler
   */
  public String handleRequest(final JsonObject event, final Context context) {
    try {
      // put requestId into ThreadContext
      ThreadContext.put("requestid", context.getRequestID());

      log.debug("debug log");
      log.info("info log");
      log.warn("warn log");
      log.error("error log");

    } finally {
      // remove requestId from ThreadContext
      ThreadContext.remove("requestid");
    }
    return "ok";
  }

}

Log output

Example Log output
12025-08-01T08:13:22Z Start invoke request '0d0c9273-61d9-4dfb-b32a-52a4372a98dc', version: latest
22025-08-01T08:13:22.792Z|0d0c9273-61d9-4dfb-b32a-52a4372a98dc|DEBUG|FGLoggingSLF4j.java:97|debug log
32025-08-01T08:13:22.792Z|0d0c9273-61d9-4dfb-b32a-52a4372a98dc|INFO|FGLoggingSLF4j.java:98|info log
42025-08-01T08:13:22.793Z|0d0c9273-61d9-4dfb-b32a-52a4372a98dc|WARN|FGLoggingSLF4j.java:99|warn log
52025-08-01T08:13:22.793Z|0d0c9273-61d9-4dfb-b32a-52a4372a98dc|ERROR|FGLoggingSLF4j.java:100|error log
62025-08-01T08:13:22Z Finish invoke request '0d0c9273-61d9-4dfb-b32a-52a4372a98dc', duration: 60.378ms, billing duration: 61ms, memory used: 104.137MB, billing memory: 512MB, cpu used: 0.195U, storage used: 0.052MB

Lines 2-5 show outputs from configured logger.

Note

If initializer is not set, log output will be as follows:

Example Log output with function initializer not set
12025-08-01T08:30:09Z Start invoke request '2146fee3-aa3b-44cb-af6a-d7d292ccf6e6', version: latest
2[2025-08-01 10:30:09.449 INFO FGLoggingSLF4j.java:98] info log
3[2025-08-01 10:30:09.453 WARN FGLoggingSLF4j.java:99] warn log
4[2025-08-01 10:30:09.453 ERROR FGLoggingSLF4j.java:100] error log
52025-08-01T08:30:09Z Finish invoke request '2146fee3-aa3b-44cb-af6a-d7d292ccf6e6', duration: 59.914ms, billing duration: 60ms, memory used: 99.527MB, billing memory: 512MB, cpu used: 0.398U, storage used: 0.052MB

Lines 2-5 show outputs from default logger configuration.

Deployment instructions:

  • Set Function execution entry point

    Choose Settings > Basic Settings, set the Function Execution Entry parameter to com.opentelekomcloud.samples.FGLoggingSLF4j.handleRequest

  • Enable class isolation.

    After the code package is successfully deployed, select Settings > Advanced Settings, turn on Class Isolation

  • Set function initialization entry point

    Choose Settings > Advanced Settings:

    • enable Initialization

    • set the Initializer parameter to com.opentelekomcloud.samples.FGLoggingSLF4j.initializer

    • set the Initialization Timeout parameter to appropriate value, e.g. 10s

  • Set Environment Variable “LOG_LEVEL”

    Choose Settings > Environment Variables and add new variable with key: LOG_LEVEL and value: DEBUG

    (Possible values are DEBUG, INFO, WARN, ERROR)

Further readings:

https://www.slf4j.org/manual.html