Skip to content

Get Data Samples from Go services

To get Data Samples from your Go services, you can use the sampler module which is provided as part of the Neblic platform code. Since Go is the primary language used by Neblic to implement its components, this library acts as the reference implementation of the Neblic Control Plane protocol, so it will always implement the latest features.

Usage

Note

All code snippets have error handling omitted for brevity

To add Samplers in your code that export Data Samples you first need to initialize a Provider. A Provider receives a configuration that is then used to configure and initialize all the Samplers in your application.

import (
    "context"

    "github.com/neblic/platform/logging"
    "github.com/neblic/platform/sampler"
)

func initProvider(t *testing.T) sampler.Provider {
    // the `Settings` struct contains the required configuration settings
    settings := sampler.Settings{
        ResourceName:      "service-name",
        ControlServerAddr: "otelcol:8899",
        DataServerAddr:    "otelcol:4317",
    }

    // additional options are provided with the `Options Pattern`
    logger, _ := logging.NewZapDev()
    provider, _ := sampler.NewProvider(context.Background(), settings, sampler.WithLogger(logger))

    // optional: It is recommended to register the `Provider` as global.
    // this will allow you to initialize a `Sampler` from anywhere in your code
    // without needing a reference to the `Provider`.
    err := sampler.SetProvider(provider)
    if err != nil {
        t.Error(err)
    }

    return provider
}

To see details about the required settings and available options, see this page.

Once the Provider is initialized, you can use it to initialize Samplers. If you have registered the provider as global, you can simply call the Sampler method from anywhere in your application. If not, you will need to call the Sampler method of your provider. They both have the same signature so the following explanation works for both options.

Info

It is not required to first initialize and register the Provider as global before creating Samplers. If a Sampler is initialized using the global provider before a Provider is registered, it will return a stubbed Sampler with no-op methods. Once the Provider is registered, it will internally replace the no-op stub with the real Sampler. This happens transparently for the application.

import (
    "github.com/neblic/platform/sampler"
    "github.com/neblic/platform/sampler/sample"
)

func initSampler() sampler.Sampler {
    // initialize the schema that the sampled `Data Samples` will
    // a `DynamicSchema` supports Json strings and Go structs
    schema := sample.NewDynamicSchema()

    // creates a Sampler using the global provider
    // the global provider can be set using the `sampler.SetProvider(...)` method
    someSampler, _ := sampler.New("sampler-name", schema)

    return someSampler
}

To see what other schemas the Go Sampler supports, check this Godoc page.

Once you have initialized the Sampler, you can call any of its methods to have it evaluate a Data Sample. It will then be evaluated by any configured Sampling Rule and exported if there is a match.

Warning

You need to be mindful of what methods you use to sample data. Depending on the schema provided when the Sampler is initialized, some methods will work better or faster than others.

As a rule of thumb, you want to provide a schema if you have it since this allows the Sampler to internally optimize how it evaluates the Sampling Rules. If you do not have it, a sampler configured with a DynamicSchema is capable of processing any type data using any of the sampling methods. See the Godoc documentation for details.

func sampleData(ctx context.Context) bool {
    var dataSample string

    // evaluate a `Data Sample`
    return someSampler.Sample(ctx, sample.JSONSample(dataSample, sample.WithKey("key")))
}

In this example, since the Sampler was initialized with a DynamicSchema, it is best to use the method SampleJson()* or *SampleNative(). These sampling methods are designed to work with samples that do not have a fixed or known schema.

gRPC interceptor

If you use gRPC servers or clients in your services, you can make use of a gRPC interceptor. They will automatically create Samplers that will efficiently intercept all requests and responses.

Internally, they create Samplers with a ProtoSchema so they do not need to deserialize the Protobuf message to evaluate its contents.

To use it, you need to initialize the interceptor and provide it when initializing the gRPC connection

import (
    "context"

    neblicgrpc "github.com/neblic/platform/sampler/instrumentation/google.golang.org/grpc"
    "google.golang.org/grpc"
)

func initInterceptor() *grpc.ClientConn {
    interceptor := neblicgrpc.UnaryClientInterceptor()
    conn, _ := grpc.DialContext(context.Background(), "server-addr:port",
        grpc.WithUnaryInterceptor(interceptor))

    return conn
}

Documentation

Check the Godoc documentation to see the sampler module documentation.