Skip to main content

GO

tip

If your code is running inside Kubernetes the best practice will be to use our kubernetes integrations.

Logs

This shipper uses goleveldb and goqueue as a persistent storage implementation of a persistent queue, so the shipper backs up your logs to the local file system before sending them. Logs are queued in the buffer and 100% non-blocking. A background Go routine ships the logs every 5 seconds.

Set up the Logz.io Golang API client

Before you begin, you'll need: Go 1.x or higher

Add the dependency to your project

Navigate to your project's folder in the command line, and run this command to install the dependency.

go get -u github.com/logzio/logzio-go

Configure the client

Use the sample in the code block below as a starting point, and replace the sample with a configuration that matches your needs.

For a complete list of options, see the configuration parameters below the code block.👇

package main

import (
"fmt"
"os"
"time"
"github.com/logzio/logzio-go"
)

func main() {
// Replace these parameters with your configuration
l, err := logzio.New(
"<<LOG-SHIPPING-TOKEN>>",
logzio.SetDebug(os.Stderr),
logzio.SetUrl("https://<<LISTENER-HOST>>:8071"),
logzio.SetDrainDuration(time.Second * 5),
logzio.SetTempDirectory("myQueue"),
logzio.SetDrainDiskThreshold(99),
)
if err != nil {
panic(err)
}

// Because you're configuring directly in the code,
// you can paste the code sample here to send a test log.
//
// The code sample is below the parameters list. 👇
}

Parameters

ParameterDescriptionRequired/Default
<<LOG-SHIPPING-TOKEN>>Your Logz.io log shipping token directs the data securely to your Logz.io Log Management account. The default token is auto-populated in the examples when you're logged into the Logz.io app as an Admin. Manage your tokens.Required
SetUrlListener URL and port. Replace <<LISTENER-HOST>> with the host for your region. The required port depends whether HTTP or HTTPS is used: HTTP = 8070, HTTPS = 8071.Required (default: https://listener.logz.io:8071)
SetDebugDebug flag.false
SetDrainDurationTime to wait between log draining attempts.5 * time.Second
SetTempDirectoryFilepath where the logs are buffered.--
SetCheckDiskSpaceTo enable SetDrainDiskThreshold, set to true. Otherwise, false.true
SetDrainDiskThresholdMaximum file system usage, in percent. Used only if SetCheckDiskSpace is set to true. If the file system storage exceeds this threshold, buffering stops and new logs are dropped. Buffering resumes if used space drops below the threshold.70.0

Code sample

msg := fmt.Sprintf("{\"%s\": \"%d\"}", "message", time.Now().UnixNano())
err = l.Send([]byte(msg))
if err != nil {
panic(err)
}

l.Stop() // Drains the log buffer

Metrics

The Logz.io Go Metrics Exporter enables you to send metrics directly from your code using the Prometheus Remote Write API. Below, you'll find a guide for setting it up, along with examples of how to manually instrument your application using the OpenTelemetry SDK.

Install the Logzio Metrics exporter

Run the following command:

go get github.com/logzio/go-metrics-sdk

Configure the exporter

Add the exporter definition to your application code:

import (
"context"
metricsExporter "github.com/logzio/go-metrics-sdk"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
m "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"log"
"time"
)

func newLogzioExporter() (*metricsExporter.Exporter, error) {
return metricsExporter.New(
metricsExporter.Config{
LogzioMetricsListener: "https://<<LISTENER-HOST>>:8053",
LogzioMetricsToken: "<<PROMETHEUS-METRICS-SHIPPING-TOKEN>>",
RemoteTimeout: 30 * time.Second,
PushInterval: 10 * time.Second,
Quantiles: []float64{0, 0.25, 0.5, 0.75, 1},
AddMetricSuffixes: true,
ExternalLabels: map[string]string{
"<<LABEL_KEY>>": "<<LABEL_VALUE>>",
},
})
}

Exporter parameters

Replace the placeholders in the code to match your specifics.

Parameter NameDescriptionRequired/OptionalDefault
LogzioMetricsListenerThe full Logz.io Listener URL for your region, configured to use port 8052 for http traffic, or port 8053 for https traffic (example: https://listener.logz.io:8053). For more details, see the regions page in logz.io docsRequiredhttps://listener.logz.io:8053
LogzioMetricsTokenThe Logz.io Prometheus Metrics account token. Find it under Settings > Manage accounts. Look up your Metrics account token.Required-
RemoteTimeoutThe timeout for requests to the remote write Logz.io metrics listener endpoint.Required30 (seconds)
PushIntervalThe time interval for sending the metrics to Logz.io.Required10 (seconds)
QuantilesThe quantiles of the histograms.Optional[0.5, 0.9, 0.95, 0.99]
HistogramBoundariesThe histogram boundaries.Optional-
ExternalLabelsAllow adding global labels to all metrics that are processed by the exporter.Optional-
AddMetricSuffixesAdds Unit suffix to the metric, if the Unit was defined.Optionalfalse

Set up the Metric Instruments Creator

Create Meter to be able to create metric instruments.

func newResource() (*resource.Resource, error) {
return resource.Merge(resource.Default(),
resource.NewWithAttributes(semconv.SchemaURL,
semconv.ServiceName("<<SERVICE_NAME>>"),
semconv.ServiceVersion("<<SERVICE_VERSION>>"),
))
}

func newMeterProvider(res *resource.Resource) (*metric.MeterProvider, error) {
metricExporter, err := newLogzioExporter()
if err != nil {
return nil, err
}

meterProvider := metric.NewMeterProvider(
metric.WithResource(res),
metric.WithReader(metric.NewPeriodicReader(metricExporter,
metric.WithInterval(60*time.Second))),
)
return meterProvider, nil
}

// create a context
con := context.Background()

// Create resource
res, err := newResource()
if err != nil {
panic(err)
}

// Create a meter provider.
meterProvider, err := newMeterProvider(res)
if err != nil {
panic(err)
}

// Handle shutdown properly so nothing leaks.
defer func() {
if err := meterProvider.Shutdown(con); err != nil {
log.Println(err)
}
}()

// Register as global meter provider so that it can be used via otel.Meter
// and accessed using otel.GetMeterProvider.
// Most instrumentation libraries use the global meter provider as default.
// If the global meter provider is not set then a no-op implementation
// is used, which fails to generate data.
otel.SetMeterProvider(meterProvider)

meter := otel.Meter("example-meter") // replace `example-meter` with any custom instrumentation meter name you'd like

Add metric instruments

Add a required metric intrument to your code. Below are the available metric instruments and their code definition.

The exporter uses the simple selector's metric.DefaultAggregationSelector(). This means that the instruments are mapped to aggregations as shown in the table below.

InstrumentBehaviorAggregation
CounterA synchronous Instrument which supports non-negative increments.Sum
Asynchronous CounterAn asynchronous Instrument which reports monotonically increasing value(s) when the instrument is being observed.Sum
HistogramA synchronous Instrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile.Histogram
Asynchronous GaugeAn asynchronous Instrument which reports non-additive value(s) when the instrument is being observed.Gauge
UpDownCounterA synchronous Instrument which supports increments and decrements.Sum
Asynchronous UpDownCounterAn asynchronous Instrument which reports additive value(s) when the instrument is being observed.Sum

Counter

// Create counter instruments
counter, err := meter.Int64Counter(
"int_counter", // name of the metric
// m.WithUnit("ms") // add a unit to the metric, if needed
m.WithDescription("Counts the total number of requests"),
)

floatCounter, err := meter.Float64Counter("float_counter") // name of the metric

// Record values to the metric instruments and add labels
counter.Add(con, 1)
counter.Add(con, 10, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))
floatCounter.Add(con, 2.5)

Asynchronous Counter

// Create callbacks for your observable counter instruments
// Float64ObservableCounter is also a supported type
observableCounter, err := meter.Int64ObservableCounter(
"observable_counter", // name of the metric
// m.WithUnit("By"), // add a unit to the metric, if needed
m.WithDescription("observable counter description"),
)

_, err = meter.RegisterCallback(
func(con context.Context, o m.Observer) error {
o.ObserveInt64(observableCounter, 10, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))
return nil
},
observableCounter,
)

Histogram

// Create Histogram instruments
intHistogram, err := meter.Int64Histogram(
"histogram-meter", // name of the metric
// m.WithUnit("seconds") // add a unit to the metric, if needed
m.WithDescription("Histogram description"),
)

floatHistogram, err := meter.Float64Histogram("float-histogram-meter") // name of the metric

// Record values to the metric instruments and add labels
intHistogram.Record(con, 2)
intHistogram.Record(con, 2, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))
floatHistogram.Record(con, 3.4)

Gauge

g, err := meter.Int64Gauge(
"g-test",
// m.WithUnit("seconds"), // add a unit to the metric, if needed
m.WithDescription("Gauge description"),
)

g.Record(con, 4)
g.Record(con, 4, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))

Asynchronous Gauge

// Create callbacks for your observable up-down counter instruments
// Float64ObservableGauge is also a supported type
observableGauge, err := meter.Int64ObservableGauge(
"observable_gauge", // name of the metric
// m.WithUnit("By"), // add a unit to the metric, if needed
m.WithDescription("observable gauge description"),
)

_, err = meter.RegisterCallback(
func(con context.Context, o m.Observer) error {
o.ObserveInt64(observableGauge, 10, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))
return nil
},
observableGauge,
)

UpDownCounter

intUpDownCounter, err := meter.Int64UpDownCounter(
"int_up_down_counter", // name of the metric
// m.WithUnit("ms"), // add a unit to the metric, if needed
m.WithDescription("Up-down counter description"),
)

floatUpDownCounter, err := meter.Float64UpDownCounter(
"float_up_down_counter", // name of the metric
m.WithDescription("Up-down counter description"),
)

intUpDownCounter.Add(con, 5)
floatUpDownCounter.Add(con, 5.6, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))

Asynchronous UpDownCounter

// Create callbacks for your observable up-down counter instruments
// Float64ObservableUpDownCounter is also a supported type
observableCounter, err := meter.Int64ObservableUpDownCounter(
"observable_up_down_counter", // name of the metric
// m.WithUnit("By"), // add a unit to the metric, if needed
m.WithDescription("observable up down counter description"),
)

_, err = meter.RegisterCallback(
func(con context.Context, o m.Observer) error {
o.ObserveInt64(observableCounter, 10, m.WithAttributes(attribute.Key("<<LABEL_KEY>>").String("<<LABEL_VALUE>>")))
return nil
},
observableCounter,
)

Check Logz.io for your metrics

Give your data some time to get from your system to ours, then log in to your Logz.io Metrics account, and open the Logz.io Metrics tab.

Install the pre-built dashboard to enhance the observability of your metrics.

To view the metrics on the main dashboard, log in to your Logz.io Metrics account, and open the Logz.io Metrics tab.

Traces

Auto Instrumentation

Deploy this integration to enable instrumentation of your Go application using OpenTelemetry.

Before you begin, you'll need:

  • A Go application without instrumentation
  • An active Logz.io account
  • Port 4318 available on your host system
  • A name defined for your tracing service. You will need it to identify the traces in Logz.io.

Install dependencies

go get -u go.opentelemetry.io/otel
go get -u go.opentelemetry.io/otel/propagation
go get -u go.opentelemetry.io/otel/sdk/resource
go get -u go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
go get -u go.opentelemetry.io/otel/sdk/trace
go get -u go.opentelemetry.io/otel/semconv/v1.26.0

Setup Tracer Provider

Create a new file otel.go and place the below code in it:

note

Change <<SERVICE-NAME>> to your own service name.

import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
"log"

"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
)

func newTraceProvider() (*sdktrace.TracerProvider, error) {
// Ensure default SDK resources and the required service name are set.
r, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("<<SERVICE-NAME>>"),
),
)
if err != nil {
return nil, err
}

exp, _ := otlptracehttp.New(context.Background(),
otlptracehttp.WithEndpoint("localhost:4318"),
otlptracehttp.WithInsecure())

return sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(r),
), nil
}

// setupOTelSDK bootstraps the OpenTelemetry logging pipeline.
func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) {
// setup trace provider
traceProvider, err := newTraceProvider()
if err != nil {
return nil, err
}

otel.SetTracerProvider(traceProvider)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))

// Return a shutdown function
shutdown = func(ctx context.Context) error {
err := traceProvider.Shutdown(ctx)
if err != nil {
log.Printf("Error during tracer provider shutdown: %v", err)
}
return err
}

return shutdown, nil
}

Call Tracer Provider from main function

Make sure the application will setup the instrumentation by calling setupOTelSDK() that was created in the previous step from your main function.

// Set up OpenTelemetry.
otelShutdown, err := setupOTelSDK(ctx)
if err != nil {
return
}
// Handle shutdown properly so nothing leaks.
defer func() {
err = errors.Join(err, otelShutdown(context.Background()))
}()

Setup OpenTelemetry Collector

Create a dedicated directory on the host of your Go application and download the OpenTelemetry collector that is relevant to the operating system of your host.

After downloading the collector, create a configuration file config.yaml with the following parameters:

receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"

exporters:
logzio/traces:
account_token: "<<TRACING-SHIPPING-TOKEN>>"
region: "<<LOGZIO_ACCOUNT_REGION_CODE>>"
headers:
user-agent: logzio-opentelemetry-traces

processors:
batch:
tail_sampling:
policies:
[
{
name: policy-errors,
type: status_code,
status_code: {status_codes: [ERROR]}
},
{
name: policy-slow,
type: latency,
latency: {threshold_ms: 1000}
},
{
name: policy-random-ok,
type: probabilistic,
probabilistic: {sampling_percentage: 10}
}
]

extensions:
pprof:
endpoint: :1777
zpages:
endpoint: :55679
health_check:

service:
extensions: [health_check, pprof, zpages]
pipelines:
traces:
receivers: [otlp]
processors: [tail_sampling, batch]
exporters: [logzio/traces]
telemetry:
logs:
level: info

Replace <<TRACING-SHIPPING-TOKEN>> with the token of the account you want to ship to.

Replace <<LOGZIO_ACCOUNT_REGION_CODE>> with the applicable region code.

Start OpenTelemetry Collector

Run the following command from the directory of your application file:

<path/to>/otelcontribcol_<VERSION-NAME> --config ./config.yaml
  • Replace <path/to> with the path to the directory where you downloaded the collector.
  • Replace <VERSION-NAME> with the version name of the collector applicable to your system, e.g. otelcontribcol_darwin_amd64.
Check Logz.io for your traces

Run the application after building it with the new Instrumentation. Give your traces some time to get from your system to ours, and then open Tracing.

Manual Instrumentation

If you're using specific libararies and want to be specific or precise with instrumentation, you can opt to instrument your code manually.