diff --git a/cmd/goweb/api.go b/cmd/goweb/api.go index be7e0b4..ab41a30 100644 --- a/cmd/goweb/api.go +++ b/cmd/goweb/api.go @@ -4,14 +4,15 @@ import ( "context" "fmt" "log" + "log/slog" "net/http" + "os" _ "net/http/pprof" "github.com/ViBiOh/httputils/v4/pkg/alcotest" "github.com/ViBiOh/httputils/v4/pkg/cors" "github.com/ViBiOh/httputils/v4/pkg/httputils" - "github.com/ViBiOh/httputils/v4/pkg/logger" "github.com/ViBiOh/httputils/v4/pkg/owasp" "github.com/ViBiOh/httputils/v4/pkg/recoverer" "github.com/ViBiOh/httputils/v4/pkg/server" @@ -33,16 +34,16 @@ func main() { client, err := newClient(ctx, config) if err != nil { - logger.Fatal(fmt.Errorf("client: %s", err)) + slog.Error("client", "err", err) + os.Exit(1) } + defer client.Close(ctx) appServer := server.New(config.appServer) - promServer := server.New(config.promServer) - go promServer.Start(client.health.End(ctx), "prometheus", client.prometheus.Handler()) - go appServer.Start(client.health.End(ctx), "http", httputils.Handler(newPort(config), client.health, recoverer.Middleware, client.prometheus.Middleware, client.tracer.Middleware, owasp.New(config.owasp).Middleware, cors.New(config.cors).Middleware)) + go appServer.Start(client.health.End(ctx), "http", httputils.Handler(newPort(config), client.health, recoverer.Middleware, client.telemetry.Middleware("http"), owasp.New(config.owasp).Middleware, cors.New(config.cors).Middleware)) client.health.WaitForTermination(appServer.Done()) - server.GracefulWait(appServer.Done(), promServer.Done()) + server.GracefulWait(appServer.Done()) } diff --git a/cmd/goweb/client.go b/cmd/goweb/client.go index 9cc507f..98a871e 100644 --- a/cmd/goweb/client.go +++ b/cmd/goweb/client.go @@ -6,39 +6,33 @@ import ( "github.com/ViBiOh/httputils/v4/pkg/health" "github.com/ViBiOh/httputils/v4/pkg/logger" - "github.com/ViBiOh/httputils/v4/pkg/prometheus" "github.com/ViBiOh/httputils/v4/pkg/request" - "github.com/ViBiOh/httputils/v4/pkg/tracer" + "github.com/ViBiOh/httputils/v4/pkg/telemetry" ) type client struct { - tracer tracer.App - logger *logger.Logger - prometheus *prometheus.App - health *health.App + telemetry telemetry.App + health *health.App } func newClient(ctx context.Context, config configuration) (client, error) { var output client var err error - output.logger = logger.New(config.logger) - logger.Global(output.logger) + logger.Init(config.logger) - output.tracer, err = tracer.New(ctx, config.tracer) + output.telemetry, err = telemetry.New(ctx, config.telemetry) if err != nil { - return output, fmt.Errorf("tracer: %w", err) + return output, fmt.Errorf("telemetry: %w", err) } - request.AddTracerToDefaultClient(output.tracer.GetProvider()) + request.AddTracerToDefaultClient(output.telemetry.GetMeterProvider(), output.telemetry.GetTraceProvider()) - output.prometheus = prometheus.New(config.prometheus) output.health = health.New(config.health) return output, nil } func (c client) Close(ctx context.Context) { - c.tracer.Close(ctx) - c.logger.Close() + c.telemetry.Close(ctx) } diff --git a/cmd/goweb/config.go b/cmd/goweb/config.go index 5137230..eab6370 100644 --- a/cmd/goweb/config.go +++ b/cmd/goweb/config.go @@ -3,7 +3,6 @@ package main import ( "flag" "os" - "time" "github.com/ViBiOh/flags" "github.com/ViBiOh/goweb/pkg/hello" @@ -12,22 +11,19 @@ import ( "github.com/ViBiOh/httputils/v4/pkg/health" "github.com/ViBiOh/httputils/v4/pkg/logger" "github.com/ViBiOh/httputils/v4/pkg/owasp" - "github.com/ViBiOh/httputils/v4/pkg/prometheus" "github.com/ViBiOh/httputils/v4/pkg/server" - "github.com/ViBiOh/httputils/v4/pkg/tracer" + "github.com/ViBiOh/httputils/v4/pkg/telemetry" ) type configuration struct { - appServer server.Config - promServer server.Config - health health.Config - alcotest alcotest.Config - logger logger.Config - tracer tracer.Config - prometheus prometheus.Config - owasp owasp.Config - cors cors.Config - hello hello.Config + appServer server.Config + health health.Config + alcotest alcotest.Config + logger logger.Config + telemetry telemetry.Config + owasp owasp.Config + cors cors.Config + hello hello.Config } func newConfig() (configuration, error) { @@ -35,15 +31,13 @@ func newConfig() (configuration, error) { fs.Usage = flags.Usage(fs) return configuration{ - appServer: server.Flags(fs, ""), - promServer: server.Flags(fs, "prometheus", flags.NewOverride("Port", uint(9090)), flags.NewOverride("IdleTimeout", 10*time.Second), flags.NewOverride("ShutdownTimeout", 5*time.Second)), - health: health.Flags(fs, ""), - alcotest: alcotest.Flags(fs, ""), - logger: logger.Flags(fs, "logger"), - tracer: tracer.Flags(fs, "tracer"), - prometheus: prometheus.Flags(fs, "prometheus", flags.NewOverride("Gzip", false)), - owasp: owasp.Flags(fs, ""), - cors: cors.Flags(fs, "cors"), + appServer: server.Flags(fs, ""), + health: health.Flags(fs, ""), + alcotest: alcotest.Flags(fs, ""), + logger: logger.Flags(fs, "logger"), + telemetry: telemetry.Flags(fs, "telemetry"), + owasp: owasp.Flags(fs, ""), + cors: cors.Flags(fs, "cors"), hello: hello.Flags(fs, ""), }, fs.Parse(os.Args[1:]) diff --git a/go.mod b/go.mod index 8b00976..a5b4d89 100644 --- a/go.mod +++ b/go.mod @@ -4,35 +4,30 @@ go 1.21 require ( github.com/ViBiOh/flags v1.3.1 - github.com/ViBiOh/httputils/v4 v4.62.0 + github.com/ViBiOh/httputils/v4 v4.63.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 ) require ( - github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect + go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect diff --git a/go.sum b/go.sum index 80ada80..9aa3249 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/ViBiOh/flags v1.3.1 h1:OHkGtVBPb6CpgWUST1VS9heKvHWBgwpyM8fXnuJRRVU= github.com/ViBiOh/flags v1.3.1/go.mod h1:yQAIBf4HTymJDCF0Bl8QQHvQTr5uiUMQBa/A/ao1oM4= -github.com/ViBiOh/httputils/v4 v4.62.0 h1:XjAl9QR1UoExQvvPmy2zmvYzoG4dRd7kHWVi0nvQHFw= -github.com/ViBiOh/httputils/v4 v4.62.0/go.mod h1:gmP4HrHGG811CpErOlJzR5CuMctmAfQ/zPU8sQQmvEU= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/ViBiOh/httputils/v4 v4.63.0 h1:gbZMAdhksMZ8ht93lB6RFLxV1V2mIvgeDh6nogV6mtE= +github.com/ViBiOh/httputils/v4 v4.63.0/go.mod h1:2wab2vFHV+FvoZqH1hGyLeJa/cYeGgqUSXWK3dfHGq4= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -21,9 +19,6 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -38,22 +33,12 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rabbitmq/amqp091-go v1.8.1 h1:RejT1SBUim5doqcL6s7iN6SBmsQqyTgXb1xMlH0h1hA= github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= -github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= -github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= +github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= @@ -62,6 +47,10 @@ go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 h1:f6BwB2OACc3FCbYVznctQ9V6KK7Vq6CjmYXJ7DeSs4E= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0/go.mod h1:UqL5mZ3qs6XYhDnZaW1Ps4upD+PX6LipH40AoeuIlwU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0 h1:rm+Fizi7lTM2UefJ1TO347fSRcwmIsUAaZmYmIGBRAo= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0/go.mod h1:sWFbI3jJ+6JdjOVepA5blpv/TJ20Hw+26561iMbWcwU= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= @@ -70,21 +59,22 @@ go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26 go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= +go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= +go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= +go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/dump/dump.go b/pkg/dump/dump.go index 7b57441..b476c06 100644 --- a/pkg/dump/dump.go +++ b/pkg/dump/dump.go @@ -5,12 +5,12 @@ import ( "fmt" "html" "io" + "log/slog" "net/http" "sort" "strings" "github.com/ViBiOh/httputils/v4/pkg/httperror" - "github.com/ViBiOh/httputils/v4/pkg/logger" ) // Handler for dump request. Should be use with net/http @@ -22,7 +22,7 @@ func Handler() http.Handler { return } - logger.Info("Dump of request\n%s", value) + slog.Info("Dump of request", "content", value) if _, err := w.Write([]byte(html.EscapeString(value))); err != nil { httperror.InternalServerError(w, err) diff --git a/pkg/hello/hello.go b/pkg/hello/hello.go index de7e83e..4261595 100644 --- a/pkg/hello/hello.go +++ b/pkg/hello/hello.go @@ -4,37 +4,33 @@ import ( "flag" "fmt" "html" + "log/slog" "net/http" "strings" "time" "github.com/ViBiOh/flags" "github.com/ViBiOh/httputils/v4/pkg/httpjson" - "github.com/ViBiOh/httputils/v4/pkg/logger" ) -// Hello represents the outputted welcome message type Hello struct { Name string `json:"greeting"` } -// Config of package type Config struct { locationName *string } -// Flags adds flags for configuring package func Flags(fs *flag.FlagSet, prefix string) Config { return Config{ locationName: flags.New("Location", "TimeZone for displaying current time").Prefix(prefix).DocPrefix("hello").String(fs, "Europe/Paris", nil), } } -// Handler for Hello request. Should be use with net/http func Handler(config Config) http.Handler { location, err := time.LoadLocation(*config.locationName) if err != nil { - logger.Error("error while loading location %s: %v", *config.locationName, err) + slog.Error("loading location", "err", err, "name", *config.locationName) } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {