Function Compute supports OpenJDK 8 and OpenJDK 11 runtime environments. This topic describes how to print logs, troubleshoot errors, and use custom modules in the Java runtime environments.

Print logs

Logs that are printed by using context.getLogger() are collected to the Logstore that you specify when you create a service.

package example;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class HelloFC implements StreamRequestHandler {

    @Override
    public void handleRequest(
            InputStream inputStream, OutputStream outputStream, Context context) throws IOException {

        context.getLogger().info("hello world");
        outputStream.write(new String("hello world").getBytes());
    }
}

After you run the preceding code, the following log is printed:

message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad891**** [INFO] hello world        
You can use the following code to print different types of logs:
  • context.getLogger().warn: prints logs of the WARN level.
  • context.getLogger().error: prints logs of the ERROR level.

Troubleshoot errors

If an error occurs when a function is being executed, Function Compute captures the error and returns an error message.

package example;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class HelloFC implements StreamRequestHandler {

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        throw new IOException("oops");
    }
} 
Run the following command to invoke the function:
s invoke -f event.json
Sample command output:
{
  "errorMessage" : "oops",
  "errorType" : "java.io.IOException",
  "errorCause" : "oops",
  "stackTrace" : [ "example.HelloFC.handleRequest(HelloFC.java:15)" ]
}
Error: Request id: 45dd8d90-6b78-cce3-087c-8bf4ebc6c9af. Error type: UnhandledInvocationError 

If an error occurs, the HTTP header in the response to function invocations contains X-Fc-Error-Type: UnhandledInvocationError. For more information about the error types in Function Compute, see Troubleshooting.

Use custom Java modules

If you want to use a custom module, package the module together with your code when you create a JAR package. In this section, OpenJDK 8 is used to demonstrate how to use Apache Maven to package an Object Storage Service (OSS) package into a Java project.

  1. Install Java and Maven.
    For more information about Java, visit the Java official website. For more information about Maven, see Installing Apache Maven.
  2. Create a Java project that has the following directory structure:
    test/src/main/java/example/App.java       
  3. Add the following content to the App.java file.
    package example;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    import com.aliyun.fc.runtime.Context;
    import com.aliyun.fc.runtime.StreamRequestHandler;
    import com.aliyun.fc.runtime.FunctionInitializer;
    
    /**
     * Hello world!
     *
     */
    public class App implements StreamRequestHandler, FunctionInitializer {
    
        public void initialize(Context context) throws IOException {
        }
    
        public void handleRequest(
                InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
            outputStream.write(new String("hello world\n").getBytes());
        }
    }             
  4. Create the pom.xml file in the root directory of the project. Add the maven-assembly-plugin plug-in to the pom.xml file. The following sample code shows the content of the file:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>example</groupId>
      <artifactId>Java-example</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>Java-example</name>
    
      <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.test.skip>true</maven.test.skip>
      </properties>
    <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <version>3.1.0</version>
              <configuration>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
                  <appendAssemblyId>false</appendAssemblyId> <!-- this is used for not append id to the jar name -->
              </configuration>
              <executions>
                  <execution>
                      <id>make-assembly</id> <!-- this is used for inheritance merges -->
                      <phase>package</phase> <!-- bind to the packaging phase -->
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                  <source>1.8</source>
                  <target>1.8</target>
              </configuration>
          </plugin>
      </plugins>
      </build>
    </project>            
  5. To reference external packages of Maven Central in the project, install dependencies based on your business requirements. OSS SDK for Java is used in this example. The pom.xml contains the following content:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>example</groupId>
      <artifactId>Java-example</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>Java-example</name>
    
      <dependencies>
        <dependency>
          <groupId>com.aliyun.fc.runtime</groupId>
          <artifactId>fc-java-core</artifactId>
          <version>1.3.0</version>
        </dependency>
        <dependency>
         <groupId>com.aliyun.oss</groupId>
         <artifactId>aliyun-sdk-oss</artifactId>
         <version>2.6.1</version>
       </dependency>
      </dependencies>
    
      <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.test.skip>true</maven.test.skip>
      </properties>
    <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <version>3.1.0</version>
              <configuration>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
                  <appendAssemblyId>false</appendAssemblyId> <!-- this is used for not append id to the jar name -->
              </configuration>
              <executions>
                  <execution>
                      <id>make-assembly</id> <!-- this is used for inheritance merges -->
                      <phase>package</phase> <!-- bind to the packaging phase -->
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                  <source>1.8</source>
                  <target>1.8</target>
              </configuration>
          </plugin>
      </plugins>
      </build>
    </project>             
  6. Run the mvn package command to package the files in the root directory of the project. The following sample command output shows compilation results:
    mvn package
    Sample command output:
    [INFO] Scanning for projects...
     ...  ....   ....
    [INFO] --------------------------< example:example >---------------------------
    [INFO] Building Java-example 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
     ...  ....   ....
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  11.681 s
    [INFO] Finished at: 2020-03-26T15:55:05+08:00
    [INFO] ------------------------------------------------------------------------          

    If the message shows that compilation failed, modify the code based on the error message.

    The compiled JAR package is in the target directory of the project folder and is named as Java-example-1.0-SNAPSHOT.jar based on the artifactId and version fields in pom.xml.

  7. Upload the JAR package in the Function Compute console.
    1. Log on to the Function Compute console.
    2. In the left-side navigation pane, click Services and Functions.
    3. In the top navigation bar, select the region where the service resides.
    4. On the Services page, find the service and click the name.
    5. On the Functions page, click the name of the function that you want to manage.
    6. On the Code tab, select Upload ZIP Package, Upload Folder, or Upload Package Using OSS from the Upload Code drop-down list to upload the JAR package.

You can also use maven-shade-plugin to package the files. You can use the preceding packaging methods in most scenarios. If you want to package JAR packages that are not managed by Maven, such as JAR packages in non-Maven repositories that you reference in resources/lib, you can use maven-jar-plugin and maven-dependency-plugin to package the JAR packages into the final JAR package.

Use Serverless Devs to perform packaging and deployment

If you use Serverless Devs to deploy applications, you can run the s build command to build the project.

  1. Create the s.yaml file in the root directory of the project. The following code shows the content of the file:
    edition: 1.0.0
    name: transform_fun
    access: default
    vars:
      region: cn-shenzhen
    services:
      fc-JavaDemo-test:
        component: devsapp/fc
        props:
          region: ${vars.region}
          service:
            name: JavaDemo
            description: helloworld
            internetAccess: true
          function:
            name: test
            handler: example.App::handleRequest
            initializer: example.App::initialize
            runtime: java8
            codeUri: ./            
  2. Run the following command to package the project files:
    s build
    Sample command output:
    [2021-12-10 03:27:34] [INFO] [S-CLI] - Start ...
    [2021-12-10 03:27:34] [INFO] [FC-BUILD] - Build artifact start...
    builder begin to build, runtime is: java8, sourceDir:  /test/demo
    running task: flow MavenTaskFlow
    running task: MavenCompileTask
    ......
    running task: CopyMavenArtifacts
    copy maven artifacts from /test/demo/target/dependency
    [2021-12-10 03:27:47] [INFO] [FC-BUILD] - Build artifact successfully.
    
    Tips for next step
    ======================
    * Invoke Event Function: s local invoke
    * Invoke Http Function: s local start
    * Deploy Resources: s deploy
    End of method: build
  3. Run the following command to deploy the function:
    s deploy           
    Sample command output:
    [2021-12-10 03:31:03] [INFO] [S-CLI] - Start ...
    [2021-12-10 03:31:04] [INFO] [FC-DEPLOY] - Using region: cn-shenzhen
    [2021-12-10 03:31:04] [INFO] [FC-DEPLOY] - Using access alias: default
    [2021-12-10 03:31:04] [INFO] [FC-DEPLOY] - Using accessKeyID: LTAI4G4cwJkK4Rza6xd9****
    [2021-12-10 03:31:04] [INFO] [FC-DEPLOY] - Using accessKeySecret: eCc0GxSpzfq1DVspnqqd6nmYNN****
     Using fc deploy type: sdk, If you want to deploy with pulumi, you can [s cli fc-default set deploy-type pulumi] to switch.
    [2021-12-10 03:31:05] [INFO] [FC-DEPLOY] - Checking Service eee exists
    [2021-12-10 03:31:06] [INFO] [FC-DEPLOY] - Checking Function eee exists
    [2021-12-10 03:31:06] [INFO] [FC-DEPLOY] - Fc detects that you have run build command for function: eee.
    [2021-12-10 03:31:06] [INFO] [FC-DEPLOY] - Using codeUri: /test/demo/.s/build/artifacts/eee/eee
    
    
    Detail:
    
    added: {}
    deleted: {}
    updated:
      LD_LIBRARY_PATH: >-
        /code/.s/root/usr/local/lib:/code/.s/root/usr/lib:/code/.s/root/usr/lib/x86_64-linux-gnu:/code/.s/root/usr/lib64:/code/.s/root/lib:/code/.s/root/lib/x86_64-linux-gnu:/code/.s/root/python/lib/python2.7/site-packages:/code/.s/root/python/lib/python3.6/site-packages:/code:/code/lib:/usr/local/lib
      PATH: >-
        /code/.s/root/usr/local/bin:/code/.s/root/usr/local/sbin:/code/.s/root/usr/bin:/code/.s/root/usr/sbin:/code/.s/root/sbin:/code/.s/root/bin:/code:/code/node_modules/.bin:/code/.s/python/bin:/code/.s/node_modules/.bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin
      NODE_PATH: /code/node_modules:/usr/local/lib/node_modules
      PYTHONUSERBASE: /code/.s/python
    
     Fc want to add/append some content to your origin environment variables for finding dependencies generated by build command.
    Do you agree with the behavior? yes
     Make service eee success.
     Make function eee/eee success.
    [2021-12-10 03:31:09] [INFO] [FC-DEPLOY] - Checking Service eee exists
    [2021-12-10 03:31:09] [INFO] [FC-DEPLOY] - Checking Function eee exists
    
    Tips for next step
    ======================
    * Display information of the deployed resource: s info
    * Display metrics: s metrics
    * Display logs: s logs
    * Invoke remote function: s invoke
    * Remove Service: s remove service
    * Remove Function: s remove function
    * Remove Trigger: s remove trigger
    * Remove CustomDomain: s remove domain
    
    
    
    fc-eee-eee:
      region:   cn-shenzhen
      service:
        name: JavaDemo
      function:
        name:       test
        runtime:    java8
        handler:    example.App::handleRequest
        memorySize: 128
        timeout:    3

Use IntelliJ IDEA to install dependencies, generate a JAR package, and then upload the package

  1. Create a Java project on your local computer. The following code shows the content of the pom.xml file:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>example</groupId>
      <artifactId>Java-example</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>Java-example</name>
      <dependencies>
        <dependency>
          <groupId>com.aliyun.fc.runtime</groupId>
          <artifactId>fc-java-core</artifactId>
          <version>1.3.0</version>
        </dependency>
        <dependency>
         <groupId>com.aliyun.oss</groupId>
         <artifactId>aliyun-sdk-oss</artifactId>
         <version>2.6.1</version>
       </dependency>
      </dependencies>
    </project>       
  2. Use IntelliJ IDEA to export JAR package configurations.
    1. Choose File > Project Structure.
      export jar
    2. In the dialog box that appears, choose Artifacts > + > JAR > From modules with dependencies.
      choose from modules with dependencies
    3. In the dialog box that appears, use the default configurations and click OK.
      ok
    4. In the top navigation bar of IntelliJ IDEA, choose Build > Build Artifacts, and then click Build or Rebuild to generate a JAR package.
      build
  3. You can upload the JAR package from the out/artifacts/example_jar directory of the project root directory to Function Compute. Log on to the Function Compute console and click the Code tab. Select Upload ZIP Package, Upload Folder, or Upload Package Using OSS from the Upload Code drop-down list to upload the JAR package.

Result

Log on to the Function Compute console. You can see that related services and functions are created. Results are returned as expected after you invoke them.