Bu örneği kullanarak uygulama günlüklerini, işlemleri ve işlem aralıklarını NewRelic'e gönderebilirsiniz. Burada Golang'ın standart kütüphanesinden HTTP yönlendiricisini kullanıyoruz. Bazı paketler (örn. logger) NewRelic'e bağlı olduğundan istediğiniz gibi geliştirebilirsiniz ama bu yine de bir noktadan başlamanıza yardımcı olmak içindir.


Dosyalar


new_relic.go


package xmiddleware

import (
"net/http"

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

type NewRelic struct {
Application *newrelic.Application
}

func (n NewRelic) Handle(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
txn := n.Application.StartTransaction(r.Pattern)
defer txn.End()

txn.SetWebRequestHTTP(r)

w = txn.SetWebResponse(w)
r = newrelic.RequestWithTransactionContext(r, txn)

next.ServeHTTP(w, r)
})
}

router.go


package xhttp

import (
"net/http"
)

type Router struct {
handler *http.ServeMux
}

func NewRouter() *Router {
return &Router{
handler: http.NewServeMux(),
}
}

func (r *Router) Handler() http.Handler {
return r.handler
}

func (r *Router) Add(path string, handler http.HandlerFunc, middlewares ...func(http.Handler) http.Handler) {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler).(http.HandlerFunc)
}

r.handler.HandleFunc(path, handler)
}

logger.go


package logger

import (
"log/slog"
"os"
"time"

"github.com/newrelic/go-agent/v3/integrations/logcontext-v2/logWriter"
"github.com/newrelic/go-agent/v3/newrelic"
)

func Configure(trace *newrelic.Application, severity string) {
var level slog.Level
if err := level.UnmarshalText([]byte(severity)); err != nil {
level = slog.LevelError
}

writer := logWriter.New(os.Stderr, trace)

slog.SetDefault(slog.New(slog.NewJSONHandler(writer, &slog.HandlerOptions{
Level: level,
ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr {
if attr.Key == slog.TimeKey {
attr.Value = slog.StringValue(attr.Value.Time().Format(time.RFC3339))
}

if attr.Key == slog.MessageKey {
attr.Key = "message"
}

return attr
},
})))
}

user.go


package api

import (
"context"
"log/slog"
"net/http"

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

type User struct{}

// HANDLERS --------------------------------------------------------------------

func (u User) Create(w http.ResponseWriter, r *http.Request) {
// This is how it is done!
txn := newrelic.FromContext(r.Context())
defer txn.End()

req := CreateRequest{}
req.Parse(txn)
req.Validate(txn)

slog.InfoContext(r.Context(), "User created")
}

func (u User) Delete(w http.ResponseWriter, r *http.Request) {
// This is not how you use it!
// When `Parse` closes `txn`, `Validate` span will be lost!
req := DeleteRequest{}
req.Parse(r.Context())
req.Validate(r.Context())

slog.Info("User deleted", "data.user_id", r.PathValue("id"))
}

// MODELS ----------------------------------------------------------------------

type CreateRequest struct{}

func (c CreateRequest) Parse(txn *newrelic.Transaction) {
defer txn.StartSegment("CreateRequest.Parse").End()

slog.Debug("parsed request")
}

func (c CreateRequest) Validate(txn *newrelic.Transaction) {
defer txn.StartSegment("CreateRequest.Validate").End()

slog.Debug("validated request")
}

type DeleteRequest struct{}

func (d DeleteRequest) Parse(ctx context.Context) {
txn := newrelic.FromContext(ctx)
defer txn.End()
defer txn.StartSegment("DeleteRequest.Parse").End()

slog.Debug("parsed request")
}

func (d DeleteRequest) Validate(ctx context.Context) {
txn := newrelic.FromContext(ctx)
defer txn.End()
defer txn.StartSegment("DeleteRequest.Validate").End()

slog.Debug("validated request")
}

main.go


package main

import (
"log"
"log/slog"
"net/http"

"rest/logger"
"rest/pkg/xhttp"
"rest/pkg/xmiddleware"
"rest/src/api"

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

func main() {
app, err := newrelic.NewApplication(
newrelic.ConfigAppName("Rest-1"),
newrelic.ConfigLicense("licence-goes-here"),
newrelic.ConfigAppLogForwardingEnabled(true),
)
if err != nil {
log.Fatalln(err)
}

logger.Configure(app, "DEBUG")

// HTTP middleware
newRelicMiddleware := (xmiddleware.NewRelic{Application: app}).Handle

// HTTP api
user := api.User{}

// HTTP router
rtr := xhttp.NewRouter()
rtr.Add("POST /api/v1/users", user.Create, newRelicMiddleware)
rtr.Add("DELETE /api/v1/users/{id}", user.Delete, newRelicMiddleware)

// HTTP server
slog.Debug("Server starting")
if err := http.ListenAndServe(":1234", rtr.Handler()); err != nil && err != http.ErrServerClosed {
slog.Error("Server start", "error", err)
} else {
slog.Debug("Server shutdown")
}
}

Test


$ curl --location --request POST 'http://localhost:1234/api/v1/users'

$ curl --location --request DELETE 'http://localhost:1234/api/v1/users/user-1'