Skip to content

Instantly share code, notes, and snippets.

@totegamma
Last active June 17, 2023 10:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save totegamma/1089a9431258bddcc32613dca2715e94 to your computer and use it in GitHub Desktop.
Save totegamma/1089a9431258bddcc32613dca2715e94 to your computer and use it in GitHub Desktop.
docker run -v $(pwd)/access.log:/log/access.log -v $(pwd)/agent.yaml:/etc/agent/agent.yaml -p4318:4318 grafana/agent
traces:
configs:
- name: default
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
remote_write:
- endpoint: xxx
basic_auth:
username: xxxxxx
password: xxx
batch:
timeout: 5s
send_batch_size: 100
logs:
configs:
- name: default
positions:
filename: /tmp/positions.yaml
scrape_configs:
- job_name: default
static_configs:
- targets: [localhost]
labels:
job: accesslog
__path__: /log/access.log
clients:
- url: xxxxxx
package main
import (
"os"
"log"
"fmt"
"bytes"
"context"
"math/rand"
"net/http"
"strconv"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
)
var (
tracer = otel.Tracer("main")
)
func main() {
cleanup, err := setupTraceProvider("localhost:4318", "example-service", "1.0.0")
if err != nil {
panic(err)
}
defer cleanup()
e := echo.New()
e.HidePort = true
e.HideBanner = true
logfile, err := os.OpenFile("access.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer logfile.Close()
e.Logger.SetOutput(logfile)
e.Use(middleware.Recover())
// /metrics と /health は計測しないようにする
skipper := otelecho.WithSkipper(
func(c echo.Context) bool {
return c.Path() == "/metrics" || c.Path() == "/health"
},
)
e.Use(otelecho.Middleware("api", skipper))
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Skipper: func(c echo.Context) bool {
return c.Path() == "/metrics" || c.Path() == "/health"
},
Format: `{"time":"${time_rfc3339_nano}",${custom},"remote_ip":"${remote_ip}",` +
`"host":"${host}","method":"${method}","uri":"${uri}","status":${status},` +
`"error":"${error}","latency":${latency},"latency_human":"${latency_human}",` +
`"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
CustomTagFunc: func(c echo.Context, buf *bytes.Buffer) (int, error) {
span := trace.SpanFromContext(c.Request().Context())
buf.WriteString(fmt.Sprintf("\"%s\":\"%s\"", "traceID", span.SpanContext().TraceID().String()))
buf.WriteString(fmt.Sprintf(",\"%s\":\"%s\"", "spanID", span.SpanContext().SpanID().String()))
return 0, nil
},
}))
e.GET("/randomprimes", genRandomPrimeNumber)
e.Logger.Fatal(e.Start(":8000"))
}
func genRandomPrimeNumber(c echo.Context) error {
ctx, span := tracer.Start(c.Request().Context(), "HandlerGet")
defer span.End()
countStr := c.QueryParam("count")
span.SetAttributes(attribute.String("count", countStr))
count, err := strconv.Atoi(countStr)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return c.JSON(http.StatusBadRequest, echo.Map{
"error": "invalid count",
})
}
var results []int
for i := 0; i < count; i++ {
randomNum := random(ctx, 1000, 10000)
primeNum := nthPrime(ctx, randomNum)
results = append(results, primeNum)
}
return c.JSON(http.StatusOK, echo.Map{
"result": results,
})
}
func setupTraceProvider(endpoint string, serviceName string, serviceVersion string) (func(), error) {
exporter, err := otlptracehttp.New(
context.Background(),
otlptracehttp.WithEndpoint(endpoint),
otlptracehttp.WithInsecure(),
)
if err != nil {
return nil, err
}
resource := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(serviceName),
semconv.ServiceVersionKey.String(serviceVersion),
)
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithResource(resource),
)
otel.SetTracerProvider(tracerProvider)
cleanup := func() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tracerProvider.Shutdown(ctx)
}
return cleanup, nil
}
// generate random number with min max
func random(ctx context.Context, min, max int) int {
_, span := tracer.Start(ctx, "random")
span.SetAttributes(attribute.Int("min", min), attribute.Int("max", max))
defer span.End()
return rand.Intn(max-min) + min
}
// calculate nth prime number
func nthPrime(ctx context.Context, n int) int {
_, span := tracer.Start(ctx, "nthPrime")
span.SetAttributes(attribute.Int("n", n))
defer span.End()
var primes []int
var i int = 2
for len(primes) < n {
var isPrime bool = true
for _, prime := range primes {
if i % prime == 0 {
isPrime = false
break
}
}
if isPrime {
primes = append(primes, i)
}
i++
}
return primes[len(primes)-1]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment