This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
docker run -v $(pwd)/access.log:/log/access.log -v $(pwd)/agent.yaml:/etc/agent/agent.yaml -p4318:4318 grafana/agent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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