The documentation you are viewing is not the latest documentation of Micronaut Oracle Cloud

Micronaut Oracle Cloud

Provides integration between Micronaut and Oracle Cloud

Version:

1 Introduction

This module provides integration between Micronaut and the Oracle Cloud SDK by giving you the ability to easily inject SDK clients into your Micronaut services and controllers. In addition to supporting the SDK’s blocking clients, the module provides reactive clients that use RxJava to provide async alternatives to the blocking clients in the SDK (an improvement upon the SDK’s 'out-of-the-box' aysnc clients). This module also includes support for Oracle Cloud (serverless) Functions and Oracle Cloud Autonomous Database.

2 Quick Start

To get started quickly Setup the Oracle Cloud CLI making sure you have run oci setup config to configure local access to Oracle Cloud.

Then add a dependency on the micronaut-oraclecloud-sdk module:

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-sdk")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-sdk</artifactId>
</dependency>

Followed by a dependency on the OCI SDK client you wish to use, for example for Object Store:

implementation("com.oracle.oci.sdk:oci-java-sdk-objectstorage")
<dependency>
    <groupId>com.oracle.oci.sdk</groupId>
    <artifactId>oci-java-sdk-objectstorage</artifactId>
</dependency>

All OCI SDK clients are supported.

3 Authentication

The following authentication providers are supported in this module:

ConfigFileAuthenticationDetailsProvider

The ConfigFileAuthenticationDetailsProvider uses a config file located at $USER_HOME/.oci/config. Specify a profile or config file path within the config file via your application.yml:

oci:
  config:
    profile: DEFAULT
    path: /custom/path/to/config/file
In the Oracle Java SDK the environment variable OCI_CONFIG_FILE doesn’t take precedence over the ~/.oci/config if the file exists. Assign the OCI_CONFIG_FILE to oci.config.path. To change the order: oci.config.path: ${OCI_CONFIG_FILE},

SimpleAuthenticationDetailsProvider

The SimpleAuthenticationDetailsProvider allows you to provide config details via standard Micronaut configuration files (application.yml).

oci:
  fingerprint: [String. The private key fingerprint]
  passphrase: [String. The private key passphrase]
  private-key: [String. The contents of your private key. Optionally, pass a path with private-key-file (see below).]
  private-key-file: [String. The path to the private key file (used in place of private-key above)]
  region: [String. Ex: us-phoenix-1]
  tenant-id: [String. The tenancy OCID]
  user-id: [String. The user OCID]

InstancePrincipalsAuthenticationDetailsProvider

If your application is running in the Oracle Cloud, you can authorize the InstancePrincipalsAuthenticationDetailsProvider to make SDK calls and utilize Instance Principal authentication. See the documentation to enable this via dynamic groups and policies, and then enable it for the Oracle Cloud environment via application-oraclecloud.yml with:

oci:
  config:
    instance-principal:
        enabled: true

ResourcePrincipalAuthenticationDetailsProvider

ResourcePrincipalAuthenticationDetailsProvider is similar to instance principals, but used for Oracle Functions (serverless). See the documentation for instructions on how to configure the necessary dynamic group rules and policies to use Resource Principal auth with your serverless functions. Once the proper configuration is complete, your Micronaut driven serverless functions will be able to use the OCI SDKs with no futher configuration needed.

4 Available Modules

The following modules are provided.

micronaut-oraclecloud-common

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-common")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-common</artifactId>
</dependency>

Provides the common functionality and sets up the following beans:

micronaut-oraclecloud-sdk

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-sdk")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-sdk</artifactId>
</dependency>

Provides support for injecting any of the available SDK client interfaces.

This module does not have a dependency on any one module. You should add these to your project as needed. For example to use Object Storage you would define a dependency on this module as well as:

implementation("com.oracle.oci.sdk:oci-java-sdk-objectstorage")
<dependency>
    <groupId>com.oracle.oci.sdk</groupId>
    <artifactId>oci-java-sdk-objectstorage</artifactId>
</dependency>

It is important to note that if you plan to build native images you also need to ensure the transitive javassist dependency is not included when adding dependencies on SDK modules using dependency exclusions. For example with Gradle:

Excluding javassist
implementation "com.oracle.oci.sdk:oci-java-sdk-objectstorage", {
    exclude module:'javassist'
}

micronaut-oraclecloud-function

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-function")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-function</artifactId>
</dependency>

Provides the OciFunction super class that you can subclass to enable the ability to write Oracle Cloud Functions in Micronaut that can utilize Micronaut dependency injection services.

micronaut-oraclecloud-function-http

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-function-http")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-function-http</artifactId>
</dependency>

Provides the HttpFunction class that can be used as a handler to write HTTP API Gateway function handlers that delegate to regular Micronaut controllers.

micronaut-oraclecloud-atp

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-atp")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-atp</artifactId>
</dependency>

Provides support for configuring the data source connection for the UCP and HikariCP connection pools by specifying Oracle Cloud Autonomous Database configuration.

The module generates the OracleWallet on startup.

micronaut-oraclecloud-micrometer

implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-micrometer")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-micrometer</artifactId>
</dependency>

Provides support for sending the Micrometer metrics to the Oracle Cloud Infrastructure Monitoring service.

5 RxJava 2 Support

In addition to the blocking clients, this module provides clients that use RxJava to allow reactive programming with Micronaut for each SDK.

You need to add the relevant OCI SDK dependency to use these clients.

For example, instead of ObjectStorageClient, you can inject ObjectStorageRxClient to use the Object Storage API:

import com.oracle.bmc.objectstorage.model.*;
import com.oracle.bmc.objectstorage.requests.*;
import com.oracle.bmc.objectstorage.responses.*;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.annotation.*;
import io.micronaut.oraclecloud.clients.rxjava2.objectstorage.ObjectStorageRxClient;
import io.micronaut.oraclecloud.core.TenancyIdProvider;
import io.reactivex.Single;

import java.util.List;
import java.util.stream.Collectors;

@Controller("/os")
public class BucketController implements BucketOperations {
    private final ObjectStorageRxClient objectStorage;
    private final TenancyIdProvider tenancyIdProvider;

    public BucketController(
            ObjectStorageRxClient objectStorage,
            TenancyIdProvider tenancyIdProvider) { (1)
        this.objectStorage = objectStorage;
        this.tenancyIdProvider = tenancyIdProvider;
    }
}
1 The ObjectStorageRxClient is injected into the constructor.

Once you have a reference to the relevant RxJava 2 client it is easier to compose non-blocking operations, the following example creates a bucket:

@Override
@Post(value = "/buckets/{name}")
public Single<String> createBucket(String name) {
    String tenancyId = tenancyIdProvider.getTenancyId();
    GetNamespaceRequest getNamespaceRequest = GetNamespaceRequest.builder()
            .compartmentId(tenancyId).build();
    return objectStorage.getNamespace(getNamespaceRequest) (1)
            .flatMap(namespaceResponse -> {
        CreateBucketRequest.Builder builder = CreateBucketRequest.builder()
                .namespaceName(namespaceResponse.getValue())
                .createBucketDetails(CreateBucketDetails.builder()
                        .compartmentId(tenancyId)
                        .name(name)
                        .build());

        return objectStorage.createBucket(builder.build()) (2)
                .map(CreateBucketResponse::getLocation); (3)
    });
}
1 First a request to obtain the namespace is sent
2 Then with the response the flatMap operator is used to send another request to create a bucket
3 Finally the location of the bucket is returned in the response

6 Oracle Functions (Serverless)

Oracle Functions are based on Project.fn. You can write simple functions targeting the Oracle Function environment by extending from the OciFunction super class.

Micronaut’s Oracle Function support can utilize GraalVM native-image running within a Docker container. This will result in extremely responsive serverless functions utilizing very few Cloud resources.

This super class enables dependency injection for the function. Note that the the function definition must conform to the following rules:

  • The class must have a public no arguments constructor

  • A public method that executes the function must be defined

  • The class must be annotated with @Singleton

Micronaut support for Oracle Functions can be combined with the OCI SDK support to give your serverless functions access to the OCI SDKs as needed.

You must have resource principal authentication properly configured in order for this example to work.

With Micronaut 2.1 and above you can create a new Oracle Function with the following command line command:

$ mn create-function-app myfunction --features oracle-function

This will create a Gradle build that sets up the Micronaut Gradle plugin. The only changes you need to make are to modify the build.gradle and alter the dockerBuild and dockerBuildNative to point at the Oracle Cloud Registry you wish the publish the docker images for the function:

dockerBuild {
    images = ["[REGION].ocir.io/[TENANCY_ID]/[REPOSITORY]/$project.name:$project.version"]
}

dockerBuildNative {
    images = ["[REGION].ocir.io/[TENANCY_ID]/[REPOSITORY]/$project.name:$project.version"]
}

The REGION should be altered to your region, the TENANCY_ID to your tenancy and the REPOSITORY to the Docker repository you wish to publish to.

Build

The following provides a serverless function example that uses the Object Storage API to list the available buckets:

import com.oracle.bmc.objectstorage.ObjectStorageClient;
import com.oracle.bmc.objectstorage.model.BucketSummary;
import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest;
import com.oracle.bmc.objectstorage.requests.ListBucketsRequest;
import io.micronaut.oraclecloud.core.TenancyIdProvider;
import io.micronaut.oraclecloud.function.OciFunction;

import javax.inject.*;
import java.util.List;
import java.util.stream.Collectors;

@Singleton
public class ListBucketsFunction extends OciFunction { (1)

    @Inject
    ObjectStorageClient objectStorageClient; (2)

    @Inject
    TenancyIdProvider tenantIdProvider;

}
1 A public class with a no argument constructor annotated with @Singleton and extending from OciFunction
2 You can use the @Inject annotation to inject SDK components

Once you have defined the function you should define a public method that is the function handler. For example:

public List<String> handleRequest() {
    GetNamespaceRequest getNamespaceRequest = GetNamespaceRequest.builder()
            .compartmentId(tenantIdProvider.getTenancyId()).build();
    String namespace = objectStorageClient.getNamespace(getNamespaceRequest).getValue();
    final ListBucketsRequest.Builder builder = ListBucketsRequest.builder();
    builder.namespaceName(namespace);
    builder.compartmentId(tenantIdProvider.getTenancyId());
    return objectStorageClient.listBuckets(builder.build())
            .getItems().stream().map(BucketSummary::getName)
            .collect(Collectors.toList());
}

The above example uses the Object Storage API to list the available buckets.

Docker Build

To build the Oracle Function you can run the ./gradlew dockerBuild command or to build the native version run ./gradlew dockerBuildNative.

Deploy

To deploy the Oracle Function as a Java function run ./gradlew dockerPush which will push the function to Oracle Container Registry.

To deploy the function as a native image you can run ./gradlew dockerPushNative which will deploy the function as a GraalVM native image.

Note that these commands will actually only publish the function to Oracle Container Registry, to make the function invokable you should use the Oracle Cloud UI to create the function or use the fn command line application to create the function from the container image:

Creating a Function from a Container Image
$ fn create function myapp myfunction [REGION].ocir.io/[TENANCY]/[REPOSITORY/[FUNCTION_NAME]:[FUNCTION_VERSION]

## For example:
$ fn create function myapp myfunction us-ashburn-1.ocir.io/mytenancy/myrepository/myfunction:1.0.0
For Java functions that do not use Native Image you will need to pass --memory 512 --timeout 120 as Java functions occupy more memory that native functions.

If you publish a new image using ./gradlew dockerPush or ./gradlerw dockerPushNative for an existing function you can also update it with fn update:

Updating an existing Function from a Container Image
$ fn update function myapp myfunction [REGION].ocir.io/[TENANCY]/[REPOSITORY/[FUNCTION_NAME]:[FUNCTION_VERSION]

7 Oracle Functions HTTP (Serverless)

The micronaut-oraclecloud-function-http module gives you the ability to write HTTP API Gateway function handlers that delegate to regular Micronaut controllers.

Since Micronaut 2.1 you can create HTTP functions using the command line or via Micronaut Launch:

Creating a new Function with the CLI
$ mn create-app myfunction --features oracle-function

You can then create your controller just as you would a normal Micronaut controller.

import com.oracle.bmc.objectstorage.ObjectStorage;
import com.oracle.bmc.objectstorage.model.BucketSummary;
import com.oracle.bmc.objectstorage.model.CreateBucketDetails;
import com.oracle.bmc.objectstorage.model.ListObjects;
import com.oracle.bmc.objectstorage.model.ObjectSummary;
import com.oracle.bmc.objectstorage.requests.*;
import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
import io.micronaut.oraclecloud.core.TenancyIdProvider;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Controller("/os")
public class BucketController {
    private final ObjectStorage objectStorage;
    private final TenancyIdProvider tenancyIdProvider;

    public BucketController(
            ObjectStorage objectStorage,
            TenancyIdProvider tenancyIdProvider) { (1)
        this.objectStorage = objectStorage;
        this.tenancyIdProvider = tenancyIdProvider;
    }
}
1 This example uses the micronaut-oraclecloud-sdk module to perform Object Storage operations, so the ObjectStorage client and TenancyIdProvider are injected.

Next, add a controller method to list all of the buckets in a compartment:

@Get("/buckets{/compartmentId}")
public List<String> listBuckets(@PathVariable @Nullable String compartmentId) {
    String compartmentOcid = compartmentId != null ? compartmentId : tenancyIdProvider.getTenancyId();
    GetNamespaceRequest getNamespaceRequest = GetNamespaceRequest.builder()
            .compartmentId(compartmentOcid).build();
    final GetNamespaceResponse namespaceResponse = objectStorage.getNamespace(getNamespaceRequest);
    final ListBucketsRequest.Builder builder = ListBucketsRequest.builder();
    builder.namespaceName(namespaceResponse.getValue());
    builder.compartmentId(compartmentOcid);
    return objectStorage.listBuckets(builder.build())
                    .getItems()
                    .stream()
                    .map(BucketSummary::getName)
                    .collect(Collectors.toList());
}

Docker Build

To build the Oracle Function you can run the ./gradlew dockerBuild command or to build the native version run ./gradlew dockerBuildNative.

Deploy

To deploy your function follow the same instructions provided for regular Oracle Functions.

API Gateway

Once you have deployed your function you’ll need to create an API Gateway to route requests to your serverless deployment. The Micronaut router will call the proper controller function based on the incoming HTTP Request Method and the path.

First, create an API Gateway by selecting 'Developer Services', then 'API Gateway' from the Oracle Cloud console dashboard.

API Gateway Menu

Click on 'Create Gateway'.

Create Gateway Button

Enter a name for the gateway, choose the compartment it is stored in and the network and subnet.

Create Gateway Button

When the gateway is ‘Active’, click ‘Deployments’, then ‘Create Deployment’.

Create Gateway Button

Provide a name for the deployment and enter a “Path Prefix”. If necessary, configure any Authentication, CORS or Rate Limiting and click ’Next’.

The path prefix must match the path you used in your controller (IE: @Controller("/os")).
Create Gateway Button

Enter route information.

  1. Enter /{path*} as the Path. This will capture all incoming requests and the Micronaut router will match the incoming path and request method with the proper controller method.

  2. Choose ANY for methods. Optionally, choose the necessary methods individually.

  3. Choose 'Oracle Functions' as the type.

  4. Choose the appropriate Oracle Functions application.

  5. Choose the function name that you used. This can be found in your function’s func.yaml file.

Create Gateway Button

Click 'Next', then review the deployment details and click 'Create'.

Review Deployment Details

Your new deployment will be listed in 'Creating' state.

Deployment Creating

When your new deployment becomes 'Active', click on the deployment to view the deployment details. Copy the 'Endpoint' - this is the base URL that you’ll use for your function invocations.

Create Gateway Button

Test your functions by appending the proper controller path and one of your controller endpoints.

Create Gateway Button

8 Oracle Autonomous Database

Oracle Cloud Autonomous Database connection information and credentials are stored in the Oracle Wallet.

Micronaut can automatically generate and download the Wallet and configure the data source.

First you need the correct version of the Oracle Database driver and required modules. To ensure you are using the right version apply the 21.1.0.0 or above Oracle Database BOM with Gradle:

implementation platform("com.oracle.database.jdbc:ojdbc-bom:21.1.0.0")

Or with Maven:

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc-bom</artifactId>
        <version>21.1.0.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

Secondly you need to add a dependency on the micronaut-oraclecloud-atp module:

runtime("io.micronaut.oraclecloud:micronaut-oraclecloud-atp")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-atp</artifactId>
    <scope>runtime</scope>
</dependency>

Then you must configure the authentication provider.

Then simply add a dependency to one of the Micronaut connection pool implementation.

Automated configuration is currently supported only for the HikariCP and UCP connection pool.

runtime("io.micronaut.sql:micronaut-jdbc-ucp")
<dependency>
    <groupId>io.micronaut.sql</groupId>
    <artifactId>micronaut-jdbc-ucp</artifactId>
    <scope>runtime</scope>
</dependency>

Or:

runtime("io.micronaut.sql:micronaut-jdbc-hikari")
<dependency>
    <groupId>io.micronaut.sql</groupId>
    <artifactId>micronaut-jdbc-hikari</artifactId>
    <scope>runtime</scope>
</dependency>

Note that micronaut-oraclecloud-atp module is compatible with Java 11+.

To use automated data source configuration from the Wallet, provide a configuration similar to the following:

application.yaml
datasources:
  default:
    ocid: ocid1.autonomousdatabase.oc1..... (1)
    walletPassword: micronaut.1 (2)
    username: foo (3)
    password: bar (4)
1 autonomous database id
2 password to encrypt the keys inside the wallet, that must be at least 8 characters long and must include at least 1 letter and either 1 numeric character or 1 special character
3 database username
4 database password
The username and password are not automatically generated and must be created in advance.

Module uses <db_name>_high as a default service alias. This can be overriden by serviceAlias property.

The wallet is of type SINGLE. Use walletType property to configure different type. See other valid options at https://docs.oracle.com/en-us/iaas/api/#/en/database/20160918/datatypes/GenerateAutonomousDatabaseWalletDetails.

9 Micrometer Support For Oracle Monitoring

The Oracle Cloud Infrastructure Monitoring service enables you to actively and passively monitor your cloud resources using the Metrics and Alarms features.

The module micronaut-oraclecloud-micrometer integrates Micronaut’s Micrometer support with the Oracle Cloud Infrastructure Monitoring service.

To begin, first add the standard dependencies for the Micronaut Micrometer module per the documentation.

Next, you need add a dependency on the micronaut-oraclecloud-micrometer module:

runtime("io.micronaut.oraclecloud:micronaut-oraclecloud-micrometer")
<dependency>
    <groupId>io.micronaut.oraclecloud</groupId>
    <artifactId>micronaut-oraclecloud-micrometer</artifactId>
    <scope>runtime</scope>
</dependency>

Don’t forget to add a dependency for the OCI SDK Monitoring module:

implementation("com.oracle.oci.sdk:oci-java-sdk-monitoring")
<dependency>
    <groupId>com.oracle.oci.sdk</groupId>
    <artifactId>oci-java-sdk-monitoring</artifactId>
</dependency>

Then you must configure the authentication provider.

You can configure this micrometer reporter using micronaut.metrics.export.oraclecloud. The most commonly changed configuration properties are listed below:

Name

Description

enabled

Whether to enable the reporter. Could disable to local dev for example. Default: true.

applicationName

Application name used as a common dimension. Default: ${micronaut.application.name}.

namespace

Metrics namespace. Required.

resourceGroup

Metrics resource group.

compartmentId

Oracle Cloud compartment id. Default: the Oracle SDK tenantId.

step

How frequently to report metrics. Default: PT1M (1 min). See java.time.Duration#parse(CharSequence).

batchSize

How many metrics send in one batch. Default: 50 (Max allowed number of metrics for current API).

descriptions

Boolean if meter descriptions should be sent to InfluxDB. Turn this off to minimize the amount of data sent on each scrape. Default: true

Example Oracle Cloud Config
micronaut:
  metrics:
    enabled: true
    export:
      oraclecloud:
        enabled: true
        namespace: test
        resourceGroup: foo

10 OCI Application Peformance Monitoring as a Tracing Endpoint

You can use Oracle Cloud Infrastructure Application Performance Monitoring (APM) as a drop-in replacement for Tracing in your Micronaut Applications.

OCI Application Performance Monitoring (APM) is a suite of services that give you insight into your applications and servers running in OCI via a small agent that runs on the machine and aggregates and reports metric data. It’s a nice service to monitor and diagnose performance issues. It also includes a Trace Explorer that is Zipkin (and Jaeger) compatible and we can use that Trace Explorer from our Micronaut applications (even without taking full advantage of APM via the Java Agent).

Add Dependencies

Micronaut Management

implementation("io.micronaut:micronaut-management")
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-management</artifactId>
</dependency>

Micronaut Tracing

implementation("io.micronaut:micronaut-tracing")
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-tracing</artifactId>
</dependency>

Brave Instrumentation

runtime("io.zipkin.brave:brave-instrumentation-http")
<dependency>
    <groupId>io.zipkin.brave</groupId>
    <artifactId>brave-instrumentation-http</artifactId>
    <scope>runtime</scope>
</dependency>

Zipkin Reporter

runtime("io.zipkin.reporter2:zipkin-reporter")
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter</artifactId>
    <scope>runtime</scope>
</dependency>

Open Tracing

implementation("io.opentracing.brave:brave-opentracing")
<dependency>
    <groupId>io.opentracing.brave</groupId>
    <artifactId>brave-opentracing</artifactId>
</dependency>

Create APM Domain

Now, in the OCI console, create an APM domain. We’ll share a single domain to group and trace all of our services. I know that may seem a bit confusing given the name ‘domain’, but think of it more like a “project group” or an “environment” (you may want to create separate domains for QA, Test, Prod, etc). Search for ‘Application Performance Monitoring’ and click on ‘Administration’.

APM Adinistration

In the left sidebar, click on ‘APM Domains’.

APM Domains

Click on ‘Create APM Domain’.

Create APM Domain

Name it, choose a compartment and enter a description.

Create APM Domain Details

Once the domain is created, view the domain details. Here you’ll need to grab a few values, so copy the data upload endpoint (#1), private key (#2), and public key (#3).

Create APM Domain

Now we have what we need to construct a URL to plug in to our application config files. The ‘Collector URL’ format requires us to construct a URL by using the data upload endpoint as our base URL and generate the path based on some choices including values from our private or public key. The format is documented here. Once we’ve constructed the URL path, we can plug it in to our application-oraclecloud.yml config.

Example Oracle Cloud Config
micronaut:
  application:
    name: demo2
tracing:
  zipkin:
    enabled: true
    sampler:
      probability: 1
    http:
      url: https://[redacted].apm-agt.us-phoenix-1.oci.oraclecloud.com
      path: /20200101/observations/public-span?dataFormat=zipkin&dataFormatVersion=2&dataKey=[public key]
    supportsJoin: false

If you want to keep these values out of the config file, you could set them as environment variables on the server like so:

Set ENV vars
export TRACING_ZIPKIN_HTTP_URL="https://[redacted].apm-agt.us-phoenix-1.oci.oraclecloud.com" export TRACING_ZIPKIN_HTTP_PATH="/20200101/observations/public-span?dataFormat=zipkin&dataFormatVersion=2&dataKey=[public key]"

Your application will now send trace information to APM.

View Trace Data in APM

Go to the APM Trace Explorer in the OCI console.

APM Trace Explorer

Choose your APM domain in the top right and the time period that you’d like to view/search.

APM Trace Explorer Choose Domain

Choose one of the available pre-configured queries across the top.

APM Trace Explorer Choose Query

View traces and spans:

APM Trace Explorer Traces

Click on a trace to view detailed info.

APM Trace Explorer Trace Details

Click on a span inside a trace to view detailed info and tagged values.

APM Trace Explorer Span Details

Read more about the Trace Explorer in the documentation.