Golang, redis transactions and not being show in new relic panel

Issue

So… I’ve been stuck on this for a couple of days now, I have followed the documentation and pears advice but does not seem to work, I’m using Golang with GRPC and implementing a new relic into it, to track transactions and overall performance, I manage to declare transaction and segments, but as far as database transactions the are not appearing in the database section, I have tried to pass the new relic context into the Redis client in the moment I do the transaction, also tried with background context, and the current transaction context, but does not seem to work. the queries are made but no data is being reported
here’s an example of what I have

1 – one of the functions that do transactions

   // updateCache ...
func updateCached(data *statemachinepkgv1.StateMachine, sessionID string, ctx context.Context) (*statemachinepkgv1.StateMachine, error) {

    //Transaction and segment logic
    
    //this does not create a brand new relic application, just gets the main instance
    relic, err := tools.InitRelic()

    if err != nil {
        log.Fatalf("failed to create/instace newrelic.NewApplication: %v", err)
    }

    txn := relic.StartTransaction("redis", nil, nil)

    defer newrelic.StartSegment(txn, "updateCached").End()
    defer newrelic.StartSegment(tools.CurrentTransaction, "updateCached").End() //tools.CurrentTransaction has the context of main web transaction stored with singleton design

    defer txn.End()

    dataParse, err := json.Marshal(data)
    if err != nil {
        return data, err
    }

    duration, err := time.ParseDuration(os.Getenv("GO_STATEMACHINE_REDIS_TIMELIFE"))
    if err != nil {
        return data, err
    }

    //REDIS LOGIC
    dbTransaction := newrelic.FromContext(ctx)
    newRelicContext := newrelic.NewContext(context.Background(), dbTransaction)

    err = masterClient.Set(newRelicContext, sessionID, string(dataParse), duration).Err()

    if err != nil {
        return data, err
    }

    return data, nil

}

2 – redis singleton

   package tools

import (
    "context"
    "os"

    "github.com/go-redis/redis/v8"
    nrredis "github.com/newrelic/go-agent/v3/integrations/nrredis-v8"
    newrelic "github.com/newrelic/go-agent/v3/newrelic"
)

var redisOpt = &redis.Options{
    Addr:     os.Getenv("GO_STATEMACHINE_REDIS_HOST") + ":" + os.Getenv("GO_STATEMACHINE_REDIS_PORT"),
    DB:       1,
    Password: os.Getenv("GO_STATEMACHINE_REDIS_PASSWORD"),
}

var Client *redis.Client = nil
var Ctx context.Context = nil

func getTransaction() *newrelic.Transaction {
    redisTransaction := newrelic.FromContext(context.Background())
    return redisTransaction
}

func init() {

    Client = redis.NewClient(redisOpt)
    Client.AddHook(nrredis.NewHook(redisOpt))

    txn := getTransaction()
    Ctx = newrelic.NewContext(context.Background(), txn)
}

func GetRedis() (*redis.Client, context.Context) {

    if Client == nil {
        Client = redis.NewClient(redisOpt)
        Client.AddHook(nrredis.NewHook(redisOpt))

        txn := getTransaction()
        Ctx = newrelic.NewContext(context.Background(), txn)

    }

    return Client, Ctx
}

3 – new relic singleton

   package tools

import (
    "context"
    "fmt"
    "log"
    "os"

    newrelic "github.com/newrelic/go-agent"
)

var RelicApplication newrelic.Application = nil
var CurrentTransaction newrelic.Transaction = nil

func init() {

    fmt.Println("INIT RELIC CREATING AT RUNTIME")
    cfg := newrelic.NewConfig("go-vozyengine-statemachine-service", os.Getenv("NRELIC_KEY"))
    cfg.Logger = newrelic.NewDebugLogger(os.Stdout)
    cfg.BrowserMonitoring.Attributes.Enabled = true
    cfg.TransactionTracer.Enabled = true
    cfg.TransactionEvents.Enabled = true
    cfg.DistributedTracer.Enabled = true
    cfg.CustomInsightsEvents.Enabled = true
    cfg.ErrorCollector.Enabled = true
    cfg.ErrorCollector.CaptureEvents = true

    var err error
    RelicApplication, err = newrelic.NewApplication(cfg)

    if err != nil {
        log.Fatalf("failed to create newrelic.NewApplication: %v", err)
    }

    fmt.Println("INIT RELIC = RETURNING")

}

func SetSubTransaction(txn newrelic.Transaction) {
    //set new current transaction
    CurrentTransaction = txn
}

func SetSubTransactionByContext(ctx context.Context) {
    fmt.Println("SETTING SUB TRANSACTION VIA CONTEXT - default set")
    txn := newrelic.FromContext(ctx)
    SetSubTransaction(txn)
}

func InitRelic() (newrelic.Application, error) {

    fmt.Println("INIT RELIC REBUG")
    if RelicApplication == nil {

        fmt.Println("INIT RELIC = NOT INIT CREATING")
        cfg := newrelic.NewConfig("go-vozyengine-statemachine-service", "29827623658187f9e25fdde2f2fee06da906NRAL")
        cfg.Logger = newrelic.NewDebugLogger(os.Stdout)
        cfg.BrowserMonitoring.Attributes.Enabled = true

        // Enabling distributed tracing will disable the cross application tracing feature. Distributed tracing is
        //  an improved version of cross-application tracing and only one can be enabled at a time.
        cfg.DistributedTracer.Enabled = true

        RelicApplication, err := newrelic.NewApplication(cfg)

        if err != nil {
            log.Fatalf("failed to create newrelic.NewApplication: %v", err)
        }

        fmt.Println("INIT RELIC = RETURNING")

        return RelicApplication, err

    } else {

        fmt.Println("INIT RELIC = ALREADY INIT RETURNING")
        return RelicApplication, nil
    }

}

any help is appreciated, thanks a lot!.

Solution

At the end with was fixed by updating all dependencies, had to upgrade GRPC version and it’s respective dependencies.

also change the context used by the redis transactions.

Here the final code

1 – example function usage

dbTransaction := newrelic.FromContext(ctx)
    newRelicContext := newrelic.NewContext(context.Background(), dbTransaction)

    data, err := tools.Client.Get(newRelicContext, id).Result()
    

2 – Redis Singleton

package tools

import (
    "context"
    "os"

    "github.com/go-redis/redis/v8"
    nrredis "github.com/newrelic/go-agent/v3/integrations/nrredis-v8"
    newrelic "github.com/newrelic/go-agent/v3/newrelic"
)

var redisOpt = &redis.Options{
    Addr:     os.Getenv("****************") + ":" + os.Getenv("*****************"),
    DB:       1,
    Password: os.Getenv("******************"),
}

var Client *redis.Client = nil
var Ctx context.Context = nil

func getTransaction() *newrelic.Transaction { return nil }

func init() {

    Client = redis.NewClient(redisOpt)
    Client.AddHook(nrredis.NewHook(redisOpt))

    txn := getTransaction()
    Ctx = newrelic.NewContext(context.Background(), txn)
}

func GetRedis() (*redis.Client, context.Context) {

    if Client == nil {
        Client = redis.NewClient(redisOpt)
        Client.AddHook(nrredis.NewHook(redisOpt))

        txn := getTransaction()
        Ctx = newrelic.NewContext(context.Background(), txn)

    }

    return Client, Ctx
}

3 – newRelic singleton

package tools

import (
    "context"
    "log"
    "os"

    newrelic "github.com/newrelic/go-agent/v3/newrelic"
)

var RelicApplication *newrelic.Application
var CurrentTransaction *newrelic.Transaction

func init() {

    log.Println("INIT RELIC CREATING AT RUNTIME")

    var err error

    RelicApplication, err = newrelic.NewApplication(
        newrelic.ConfigAppName("**********************"),
        newrelic.ConfigLicense(os.Getenv("NRELIC_KEY")),
        newrelic.ConfigDebugLogger(os.Stdout),
        newrelic.ConfigDistributedTracerEnabled(true),
        func(config *newrelic.Config) {
            config.Enabled = true
        },
    )

    if err != nil {
        log.Println("ERROR INITING NEW RELIC: ", err)
    }

    log.Println("INIT RELIC = RETURNING")

}

func SetSubTransaction(txn *newrelic.Transaction) {
    //set new current transaction
    CurrentTransaction = txn
}

func SetSubTransactionByContext(ctx context.Context) {
    txn := newrelic.FromContext(ctx)
    SetSubTransaction(txn)
}

func InitRelic() (*newrelic.Application, error) {

    if RelicApplication == nil {

        var err error

        writer, err := os.OpenFile("log_file", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
        if err != nil {
            log.Println("ERROR OPENING LOG FILE: ", err)
            return nil, err
        }

        RelicApplication, err = newrelic.NewApplication(
            newrelic.ConfigAppName("**********************"),
            newrelic.ConfigLicense(os.Getenv("NRELIC_KEY")),
            newrelic.ConfigDebugLogger(os.Stdout),
            newrelic.ConfigInfoLogger(writer),
            newrelic.ConfigDistributedTracerEnabled(true),
            func(config *newrelic.Config) {
                config.Enabled = false
            },
        )

        if err != nil {
            log.Println("ERROR INITING NEW RELIC: ", err)
        }

        return RelicApplication, err

    } else {

        return RelicApplication, nil
    }

}

Answered By – Andrew Alizaga

Answer Checked By – Senaida (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.