openobserve / otlp-go-sample-all-in-one

otlp-go-sample-all-in-one
0 stars 0 forks source link

how to send log to openobserve log, not in trace event log attribute #1

Closed ddatsh closed 3 weeks ago

ddatsh commented 3 weeks ago

I want to send the log directly to OpenObserve log, use such as slog

127.0.0.1:5080/api/default/default/_json accept pure json format 1

go.opentelemetry.io\otel\exporters\otlp\otlplog\otlploghttp@v0.6.0\client.go use application/x-protobuf format

package main

import (
    "context"
    "fmt"
    "go.opentelemetry.io/contrib/bridges/otelslog"
    "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
    "go.opentelemetry.io/otel/log/global"
    "go.opentelemetry.io/otel/sdk/log"
)

func main() {
    ctx := context.Background()
    //authHeaderValue := "Basic " + EncodeBase64("i@ddatsh.com"+":"+"admin")
    authHeaderValue := "Basic aUBkZGF0c2guY29tOmNkdUwyNGJOTDhrSmNYM3M="
    authHeader := map[string]string{
        "Authorization": authHeaderValue,
        "stream-name":   "default",
    }
    exporter, _ := otlploghttp.New(ctx,
        otlploghttp.WithEndpoint("127.0.0.1:5080"),
        otlploghttp.WithURLPath("/api/default/default/_json"),
        otlploghttp.WithInsecure(),
        otlploghttp.WithHeaders(authHeader),
        otlploghttp.WithCompression(0),
    )

    // Create a log record processor pipeline.
    processor := log.NewBatchProcessor(exporter)

    // Create a logger provider.
    // You can pass this instance directly when creating a log bridge.
    provider := log.NewLoggerProvider(
        log.WithProcessor(processor),
    )

    // Handle shutdown properly so that nothing leaks.
    defer func() {
        err := provider.Shutdown(context.Background())
        if err != nil {
            fmt.Println(err)
        }
    }()

    global.SetLoggerProvider(provider)

    logger := otelslog.NewLogger("my/pkg/name", otelslog.WithLoggerProvider(provider))
    logger.Info("test")
}
Manazsharma commented 3 weeks ago

You should try using a custom HTTP client in Go to send logs directly to O2, we can control the format and headers of the HTTP requests. This allows us to send logs in pure JSON format, which OpenObserve’s ingestion API requires. Refer to https://pkg.go.dev/net/http to create and send HTTP requests using the http.NewRequest and http.Client.Do methods. It should look somewhat like this although you have to Define a LogEntry struct for JSON log data and marshal it using json.Marshal

req, err := http.NewRequestWithContext(ctx, "POST", "http://127.0.0.1:5080/api/default/default/_json", bytes.NewBuffer(logData))
if err != nil {
    fmt.Println("Error creating request:", err)
    return
}

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
    fmt.Println("Error sending request:", err)
    return
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
    fmt.Printf("Failed to send log entry, status code: %d\n", resp.StatusCode)
} else {
    fmt.Println("Log entry sent successfully")
}
ddatsh commented 3 weeks ago

solved /api/default/v1/logs

package main

import (
    "context"
    "encoding/base64"
    "fmt"
    "go.opentelemetry.io/contrib/bridges/otelslog"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/log/global"
    "go.opentelemetry.io/otel/propagation"
    "go.opentelemetry.io/otel/sdk/log"
    "go.opentelemetry.io/otel/sdk/resource"
    tracesdk "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
)

func main() {
    ctx := context.Background()

    auth := "Basic " + base64.StdEncoding.EncodeToString([]byte("i@ddatsh.com:admin"))
    authHeader := map[string]string{
        "Authorization": auth,
        "stream-name":   "default",
    }
    logExporter, _ := otlploghttp.New(ctx,
        otlploghttp.WithEndpoint("127.0.0.1:5080"),
        otlploghttp.WithURLPath("/api/default/v1/logs"),
        otlploghttp.WithInsecure(),
        otlploghttp.WithHeaders(authHeader),
        otlploghttp.WithCompression(1),
    )

    // Create a logger provider.
    // You can pass this instance directly when creating a log bridge.
    lp := log.NewLoggerProvider(
        log.WithProcessor(log.NewBatchProcessor(logExporter)),
    )

    // Handle shutdown properly so that nothing leaks.
    defer func() {
        err := lp.Shutdown(context.Background())
        if err != nil {
            fmt.Println(err)
        }
    }()

    global.SetLoggerProvider(lp)

    traceClientHttp := otlptracehttp.NewClient(
        otlptracehttp.WithEndpointURL("http://127.0.0.1:5080/api/default/v1/traces"),
        otlptracehttp.WithInsecure(), otlptracehttp.WithHeaders(authHeader))
    otlptracehttp.WithCompression(1)

    exporter, _ := otlptrace.New(ctx, traceClientHttp)

    tp := tracesdk.NewTracerProvider(
        // Always be sure to batch in production.
        tracesdk.WithBatcher(exporter),
        // Record information about this application in a Resource.
        tracesdk.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("api"),
            attribute.String("environment", "prod"))),
    )
    defer func() {
        err := tp.Shutdown(context.Background())
        if err != nil {
            fmt.Println(err)
        }
    }()
    otel.SetTracerProvider(tp)
    otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))

    ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "test")
    span.AddEvent("test event")
    defer span.End()

    logger := otelslog.NewLogger("api", otelslog.WithLoggerProvider(lp))
    logger.InfoContext(ctx, "shutdown service")

}

btw trace to view log, settings organization parameters > trace id/span id field name from traceId/spanId > trace_id/span_id