Instrumenting an Azure Cosmos application with Instana Go Tracer SDK

Angith Jayan
IBM Cloud
Published in
4 min readMay 9, 2024

IBM Instana Go Tracer is an SDK that collects traces, metrics, logs, and profiles for Go applications. It provides instrumentation support for several commonly used Go packages. Instacosmos is the latest instrumentation package from the Instana Go tracer SDK that helps to bring observability into Go applications that use the Azure Cosmos DB. The APIs are designed to minimize overhead in adopting Instacosmos if you are familiar with the Azure azcosmos package. This instrumentation package primarily encompasses essential details, such as database name, container name, Cosmos endpoint, partition key, and the corresponding SQL query for each operation.

Azure Cosmos DB is a fully managed NoSQL and relational database for modern app development. It is a globally distributed, multi-model database service provided by Microsoft Azure that can simplify and expedite development by being the single AI database for the applications. It supports all the operational data models, including relational, document, vector, key-value, graph, and table.

The azure-sdk-for-go repository is for the active development of the Azure SDK for Go and it contains the Azure Cosmos DB SDK for the client applications to connect to Azure Cosmos DB.

This article discusses the process of instrumenting the Azure Cosmos DB SDK for Instana’s Go tracer and integrating instacosmos into your application.

Instrumenting Azure Cosmos DB SDK: A development perspective

Injecting tracer

All libraries often have an option to inject the tracer implementation. Interestingly, the azcosmos library also provides this option.
So, to instrument the library, an instance of Provider struct can be created in the azcore library in Azure SDK and passed through the ClientOptions as shown in the following snippet:

instacosmos.NewClientWithKey(collector, endpoint, cred,
&azcosmos.ClientOptions{
ClientOptions: policy.ClientOptions{
TracingProvider: tracing.NewProvider(func(name, version string) tracing.Tracer {
// implement the instrumentation
// return tracer
}),
},
})

However, the azcosmos library currently does not support the TracingProvider option even though it allows the tracer to pass through it. So manually instrumenting the azcosmos SDK was the only feasible option.

Photo by Greg Rakozy on Unsplash

Manually instrumenting the azcosmos SDK

In manual instrumentation, a client interface is provided that wraps the methods supplied by the ContainerClient struct in the azcosmos library. So, instead of a pointer to the instance of ContainerClient struct (azcosmos.ContainerClient), you are provided with the ContainerClient interface from instacosmos. Currently, instacosmos supports the following methods:

· CreateItem

· DeleteItem

· ExecuteTransactionalBatch

· ID

· NewQueryItemsPager

· NewTransactionalBatch

· PatchItem

· Read

· ReadItem

· ReadThroughput

· Replace

· ReplaceItem

· ReplaceThroughput

· UpsertItem

Getting the ContainerClient instance from azcosmos

The following code illustrates how you can create an instance of azcosmos.ContainerClient:

cred, err := azcosmos.NewKeyCredential("myAccountKey")
handle(err)
client, err := azcosmos.NewClientWithKey("myAccountEndpointURL", cred, nil)
handle(err)
container, err := client.NewContainer("myDatabase", "myContainer")
handle(err)

You must create an instance azcosmos.Client and it can be used to create the container and database instances.

Getting the ContainerClient interface from instacosmos

The following code illustrates how you can get the ContainerClient interface from instacosmos:

 t := instana.InitCollector(&instana.Options{
Service: "cosmos-example",
})
cred, err := instacosmos.NewKeyCredential("myAccountKey")
handle(err)
client, err := instacosmos.NewClientWithKey(t, "myAccountEndpointURL", cred, &azcosmos.ClientOptions{})
handle(err)
containerClient, err := client.NewContainer(dbName, containerName)
handle(err)

Integrating instacosmos into your Go application

The process of using the instrumented library closely resembles that of using the actual SDK for client applications to connect to Azure Cosmos DB. The instacosmos module provides the following functions to obtain the Azure Cosmos DB client:

  • NewClient
  • NewClientFromConnectionString
  • NewClientWithKey

These functions serve as wrappers for the identically named functions in the azcosmos library. Notably, unlike the original functions, instana.TraceLogger needs to be passed additionally. These functions return an interface that offers the functionalities of azcosmos.Client. By using this interface, call the NewContainer method to acquire the ContainerClient interface. This interface consists of all the methods supported by the ContainerClient struct in azcosmos.

Photo by Robert Wiedemann on Unsplash

Example

 t := instana.InitCollector(&instana.Options{
Service: "cosmos-example",
})
cred, err := instacosmos.NewKeyCredential(cosmosKey)
if err != nil {
log.Fatal("Failed to create KeyCredential:", err)
}
client, err := instacosmos.NewClientWithKey(t, cosmosEndpoint, cred, &azcosmos.ClientOptions{})
if err != nil {
log.Fatal("Failed to create cosmos DB client:", err)
}
containerClient, err := client.NewContainer(dbName, containerName)
if err != nil {
log.Fatal("Failed to create a container client:", err)
}
pk := containerClient.NewPartitionKeyString("newPartitionKey")
item := map[string]string{
"id": "anId",
"value": "2",
"myPartitionKey": "newPartitionKey",
}
marshalled, err := json.Marshal(item)
if err != nil {
log.Fatal("Failed to marshal span data:", err)
}
itemResponse, err := containerClient.CreateItem(context.Background(), pk, marshalled, nil)
if err != nil {
log.Print("Failed to create the item:", err)
}

Output

After you successfully instrument the Azure Cosmos DB into your application, you can seamlessly visualize the trace within the Instana UI as shown in the following image:

Related Documentation

- Azure SDK For Go

- Azure Cosmos DB SDK

- instacosmos

- Example

To report any issues, suggest improvements, or contribute to the development of SDK, go to the public GitHub repository and open an issue.

--

--

Angith Jayan
IBM Cloud
0 Followers
Writer for

Golang Developer | Software Engineer @ IBM | Specialized in Backend Programming