Please take the OpenCensus user survey

Go driver

Introduction

A wrapper for the official MongoDB Go driver has been instrumented with OpenCensus for Tracing and metrics at https://github.com/opencensus-integrations/gomongowrapper

Pre-requisites

Using it

To install the wrapper, please run this command

go get -u -v github.com/opencensus-integrations/gomongowrapper/...

and then in your code, just exactly like you would when using the original driver (except now with the new import)

import (
        "context"
        "log"

        "github.com/opencensus-integrations/gomongowrapper"
)

func main() {
        client, err := mongowrapper.NewClient(MONGO_URL)
        if err != nil {
                log.Fatalf("Failed to create the new client: %v", err)
        }
        ctx := context.Background()
        if err := client.Connect(ctx); err != nil {
                log.Fatalf("Failed to open client connection: %v", err)
        }
        defer client.Disconnect(ctx)
}

Instrumentation

The designers of the official MongoDB Go driver ensured that each method takes in a context.Context.

Fortunately for us, this permits context propagation, which is the mechanism with which observability signals are propagated across RPCs and over the wire.

Enabling tracing

To enable trace continuity, just use the same context that contains your traces and at some point, to consume the produced traces, please enable a Trace exporter

For example

        // Start a span like your application would start one.
        ctx, span := trace.StartSpan(context.Background(), "Fetch")
        defer span.End()

        // Now for the mongo connections, using the context
        // with the span in it for continuity.
        client, err := mongowrapper.NewClient("mongodb://localhost:27017")
        if err != nil {
                log.Fatalf("Failed to create the new client: %v", err)
        }
        if err := client.Connect(ctx); err != nil {
                log.Fatalf("Failed to open client connection: %v", err)
        }
        defer client.Disconnect(ctx)
        coll := client.Database("the_db").Collection("music")

Enabling metrics

To enable metrics, just use the same context that contains your metrics or tags and at some point, to consume the produced metrics, please enable a Metrics exporter

However, most importantly, please make sure to invoke gomongowrapper.RegisterAllViews

import (
	"log"

	"github.com/opencensus-integrations/gomongowrapper"
)

if err := gomongowrapper.RegisterAllViews(); err != nil {
	log.Fatalf("Failed to register MongoDB views: %v", err)
}

Enabling exporters

Please select your target Go trace and metrics exporters from Go exporters

Metrics

Metric Query Suffix Description Aggregation Tags
Latency “mongo/client/latency” The latencies of the various calls in milliseconds Distribution “method”, “status”, “error”
Calls “mongo/client/calls” The various calls Count “method”, “status”, “error”

Tags

As per Metrics, we have a couple of tags applied to some measurements to provide metrics

method

The tag key “method” will have a fully qualified name such as

    "github.com/mongodb/mongo-go-driver.Client.EndSession"

to distinguish between the various calls as per Instrumentation matrix

status

The tag key “status” will be either one of the following values

error

The tag key “error” will contain a description of the encountered error.

Instrumentation matrix

This is the full list of methods that have been instrumented with tracing and metrics

Method Method Name
Client.Connect “github.com/mongodb/mongo-go-driver.Client.Connect”
Client.Disconnect github.com/mongodb/mongo-go-driver.Client.Disconnect
Client.ListDatabaseNames “github.com/mongodb/mongo-go-driver.Client.ListDatabaseNames”
Client.ListDatabases “github.com/mongodb/mongo-go-driver.Client.ListDatabases”
Client.Ping “github.com/mongodb/mongo-go-driver.Client.Ping”
Collection.Aggregate “github.com/mongodb/mongo-go-driver.Collection.Aggregate”
Collection.BulkWrite “github.com/mongodb/mongo-go-driver.Collection.BulkWrite”
Collection.Count “github.com/mongodb/mongo-go-driver.Collection.Count”
Collection.CountDocuments “github.com/mongodb/mongo-go-driver.Collection.CountDocuments”
Collection.DeleteMany “github.com/mongodb/mongo-go-driver.Collection.DeleteMany”
Collection.DeleteOne “github.com/mongodb/mongo-go-driver.Collection.DeleteOne”
Collection.Distinct “github.com/mongodb/mongo-go-driver.Collection.Distinct”
Collection.Drop “github.com/mongodb/mongo-go-driver.Collection.Drop”
Collection.EstimatedDocumentCount “github.com/mongodb/mongo-go-driver.Collection.EstimatedDocumentCount”
Collection.Find “github.com/mongodb/mongo-go-driver.Collection.Find”
Collection.FindOne “github.com/mongodb/mongo-go-driver.Collection.FindOne”
Collection.FindOneAndDelete “github.com/mongodb/mongo-go-driver.Collection.FindOneAndDelete”
Collection.FindOneAndReplace “github.com/mongodb/mongo-go-driver.Collection.FindOneAndReplace”
Collection.FindOneAndUpdate “github.com/mongodb/mongo-go-driver.Collection.FindOneAndUpdate”
Collection.InsertMany “github.com/mongodb/mongo-go-driver.Collection.InsertMany”
Collection.InsertOne “github.com/mongodb/mongo-go-driver.Collection.InsertOne”
Collection.ReplaceOne “github.com/mongodb/mongo-go-driver.Collection.ReplaceOne”
Collection.UpdateMany “github.com/mongodb/mongo-go-driver.Collection.UpdateMany”
Collection.UpdateOne “github.com/mongodb/mongo-go-driver.Collection.UpdateOne”
Collection.Watch “github.com/mongodb/mongo-go-driver.Collection.Watch”
Database.Drop “github.com/mongodb/mongo-go-driver.Database.Drop”
Database.ListCollections “github.com/mongodb/mongo-go-driver.Database.ListCollections”
Database.RunCommand “github.com/mongodb/mongo-go-driver.Database.RunCommand”
Session.AbortTransaction “github.com/mongodb/mongo-go-driver.Session.AbortTransaction”
Session.CommitTransaction “github.com/mongodb/mongo-go-driver.Session.CommitTransaction”
Session.EndSession “github.com/mongodb/mongo-go-driver.Client.EndSession”

End to end example

Assuming that you already have a MongoDB server running at “localhost:27017”

package main

import (
	"context"
	"log"
	"time"

	"github.com/mongodb/mongo-go-driver/bson"

	"github.com/opencensus-integrations/gomongowrapper"

	"contrib.go.opencensus.io/exporter/stackdriver"
	"go.opencensus.io/stats/view"
	"go.opencensus.io/trace"
)

func main() {
	// Enabling the OpenCensus exporter.
	// Just using Stackdriver since it has both Tracing and Metrics
	// and is easy to whip up. Add your desired one here.
	sde, err := stackdriver.NewExporter(stackdriver.Options{
		ProjectID:    "census-demos",
		MetricPrefix: "mongosample",
	})
	if err != nil {
		log.Fatalf("Failed to create Stackdriver exporter: %v", err)
	}
	view.RegisterExporter(sde)
	trace.RegisterExporter(sde)
	if err := mongowrapper.RegisterAllViews(); err != nil {
		log.Fatalf("Failed to register all views: %v\n", err)
	}

	defer func() {
		<-time.After(2 * time.Minute)
	}()

	// Start a span like your application would start one.
	ctx, span := trace.StartSpan(context.Background(), "Fetch", trace.WithSampler(trace.AlwaysSample()))
	defer span.End()

	// Now for the mongo connections, using the context
	// with the span in it for continuity.
	client, err := mongowrapper.NewClient("mongodb://localhost:27017")
	if err != nil {
		log.Fatalf("Failed to create the new client: %v", err)
	}
	if err := client.Connect(ctx); err != nil {
		log.Fatalf("Failed to open client connection: %v", err)
	}
	defer client.Disconnect(ctx)
	coll := client.Database("the_db").Collection("music")

	q := bson.M{"name": "Examples"}
	cur, err := coll.Find(ctx, q)
	if err != nil {
		log.Fatalf("Find error: %v", err)
	}

	for cur.Next(ctx) {
		elem := make(map[string]int)
		if err := cur.Decode(elem); err != nil {
			log.Printf("Decode error: %v", err)
			continue
		}
		log.Printf("Got result: %v\n", elem)
	}
	log.Print("Done iterating")

	_, err = coll.DeleteMany(ctx, q)
	if err != nil {
		log.Fatalf("Failed to delete: %v", err)
	}
}

Results

After running the above sample, and examining the results by visiting

Resource URL
Traces on Stackdriver https://console.cloud.google.com/traces/traces
Metrics on Stackdriver https://console.cloud.google.com/traces/monitoring
Traces screenshots

Trace

Metrics screenshots

References

Resource URL
MongoDB website https://www.mongodb.com/
Official MongoDB Go driver https://godoc.org/github.com/mongodb/mongo-go-driver/mongo
OpenCensus wrapper for MongoDB Go driver https://godoc.org/github.com/opencensus-integrations/gomongowrapper