Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ As of now, Mantis has all of the core features needed to be used in almost any s
- JSON Path support
- Support for a Wiremock's `Scenario`-like feature
- Simulate production environments more accurately by defining delays on responses
- Opentelemetry traces support
- More to come

## Running It
Expand Down
2 changes: 1 addition & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ Display differences when no match is found
Add delay option to response (normal distribution)
Remove americanas-go/log dependency
Possibly remove americanas-go/config dependency
APM/Metrics (Opentelemetry integration)
Add Metrics (Opentelemetry)
Performance tests
Improve/refactor validation
6 changes: 6 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ import (
"os"
"os/signal"

amercfg "github.com/americanas-go/config"
"github.com/americanas-go/log"
"github.com/dubonzi/mantis/pkg/config"
"go.uber.org/fx"
)

func main() {
config.SetDefaultConfig()
amercfg.Load()

stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)

setupOtel()

app := fx.New(
mainModule(),
)
Expand Down
24 changes: 15 additions & 9 deletions cmd/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import (
"context"
"fmt"

"github.com/americanas-go/config"
amercfg "github.com/americanas-go/config"
"github.com/americanas-go/log"
"github.com/americanas-go/log/contrib/go.uber.org/zap.v1"
"github.com/dubonzi/mantis/pkg/app"
"github.com/gofiber/contrib/otelfiber"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/pprof"
"go.uber.org/fx"
)

func mainModule() fx.Option {
loadDefaultConfig()
config.Load()
log.SetGlobalLogger(zap.NewLoggerWithOptions(zapOptions()))

return fx.Options(
Expand Down Expand Up @@ -43,19 +42,22 @@ func serverModule() fx.Option {
srv := fiber.New(
fiber.Config{
AppName: "Mantis Server",
DisableStartupMessage: config.Bool("server.disableStartupMessage"),
DisableStartupMessage: amercfg.Bool("server.disableStartupMessage"),
},
)

srv.Use("/*", fiberErrorLogger)
if amercfg.Bool("otel.enabled") {
srv.Use(otelfiber.Middleware(otelfiber.WithSpanNameFormatter(fiberOtelSpanFormatter)))
}
srv.Use(pprof.New())
srv.Use("/*", fiberErrorLogger)
srv.All("/*", handler.All)

lc.Append(
fx.Hook{
OnStart: func(c context.Context) error {
go func() {
if err := srv.Listen(":" + config.String("server.port")); err != nil {
if err := srv.Listen(":" + amercfg.String("server.port")); err != nil {
panic(fmt.Errorf("error starting mantis server: %s", err))
}
}()
Expand All @@ -77,7 +79,7 @@ func healthModule() fx.Option {
srv := fiber.New(
fiber.Config{
AppName: "Mantis Health Server",
DisableStartupMessage: config.Bool("server.disableStartupMessage"),
DisableStartupMessage: amercfg.Bool("server.disableStartupMessage"),
},
)

Expand All @@ -87,7 +89,7 @@ func healthModule() fx.Option {
fx.Hook{
OnStart: func(c context.Context) error {
go func() {
if err := srv.Listen(":" + config.String("health.port")); err != nil {
if err := srv.Listen(":" + amercfg.String("health.port")); err != nil {
panic(fmt.Errorf("error starting health server: %s", err))
}
}()
Expand All @@ -103,7 +105,7 @@ func healthModule() fx.Option {
}

func fxLogger() fx.Option {
if config.Bool("fx.log.enable") {
if amercfg.Bool("fx.log.enable") {
return fx.Provide()
}
return fx.NopLogger
Expand All @@ -116,3 +118,7 @@ func fiberErrorLogger(c *fiber.Ctx) error {
}
return err
}

func fiberOtelSpanFormatter(ctx *fiber.Ctx) string {
return fmt.Sprintf("%s %s", ctx.Context().Method(), ctx.Request().URI().Path())
}
20 changes: 20 additions & 0 deletions cmd/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"github.com/americanas-go/config"
igzap "github.com/americanas-go/log/contrib/go.uber.org/zap.v1"
)

func zapOptions() *igzap.Options {
return &igzap.Options{
Console: struct {
Enabled bool
Level string
Formatter string
}{
Enabled: true,
Level: config.String("log.level"),
Formatter: config.String("log.format"),
},
}
}
68 changes: 68 additions & 0 deletions cmd/telemetry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package main

import (
"context"

"github.com/americanas-go/config"
"github.com/americanas-go/log"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace/noop"
)

const (
protocolHTTP = "http"
protocolGRPC = "grpc"
)

func setupOtel() {
if !config.Bool("otel.enabled") {
return
}

exporterProtocol := config.String("otel.exporter.protocol")
var err error
var traceExporter *otlptrace.Exporter

switch exporterProtocol {
case protocolHTTP:
opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(config.String("otel.exporter.endpoint"))}
if config.Bool("otel.exporter.insecure") {
opts = append(opts, otlptracehttp.WithInsecure())
}
traceExporter, err = otlptracehttp.New(context.Background(), opts...)
case protocolGRPC:
opts := []otlptracegrpc.Option{otlptracegrpc.WithEndpoint(config.String("otel.exporter.endpoint"))}
if config.Bool("otel.exporter.insecure") {
opts = append(opts, otlptracegrpc.WithInsecure())
}
traceExporter, err = otlptracegrpc.New(context.Background(), opts...)
default:
log.Warnf("opentelemetry: invalid protocol: %s", exporterProtocol)
otel.SetTracerProvider(noop.NewTracerProvider())
return
}
if err != nil {
log.Error("error starting opentelemetry exporter", err)
return
}

tp := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
trace.WithBatcher(traceExporter),
trace.WithResource(
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("mantis"),
)),
)

otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
}
20 changes: 12 additions & 8 deletions docs/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

You can configure Mantis either by envinroment variables or by passing arguments when running the executable.

| Env | Arg | Default | |
| ---------------------- | ----------------------- | ---------------- | ---------------------- |
| `SERVER_PORT` | `-server.port` | `8080` | Port Mantis runs on |
| `HEALTH_PORT` | `-health.port` | `8081` | Health check port |
| `LOADER_PATH_MAPPING` | `-loader.path.mapping` | `files/mapping` | Path to mapping files |
| `LOADER_PATH_RESPONSE` | `-loader.path.response` | `files/response` | Path to response files |
| `LOG_LEVEL` | `-log.level` | `INFO` | Log level |
| `LOG_FORMAT` | `-log.format` | `TEXT` | Log format (TEXT/JSON) |
| Env | Arg | Default | |
| ------------------------ | ------------------------- | ---------------- | -------------------------------------------------------------------- |
| `SERVER_PORT` | `-server.port` | `8080` | Port Mantis runs on |
| `HEALTH_PORT` | `-health.port` | `8081` | Health check port |
| `LOADER_PATH_MAPPING` | `-loader.path.mapping` | `files/mapping` | Path to mapping files |
| `LOADER_PATH_RESPONSE` | `-loader.path.response` | `files/response` | Path to response files |
| `OTEL_ENABLED` | `-otel.enabled` | `true` | Enable/disable Opentelemetry support |
| `OTEL_EXPORTER_PROTOCOL` | `-otel.exporter.protocol` | `http` | Protocol used to export Opentelemetry traces and metrics (http/grpc) |
| `OTEL_EXPORTER_ENDPOINT` | `-otel.exporter.endpoint` | `localhost:4318` | Endpoint of the collecter for Opentelemetry traces and metrics |
| `OTEL_EXPORTER_INSECURE` | `-otel.exporter.insecure` | `true` | Use insecure connection for Opentelemetry exporter |
| `LOG_LEVEL` | `-log.level` | `INFO` | Log level |
| `LOG_FORMAT` | `-log.format` | `TEXT` | Log format (TEXT/JSON) |
1 change: 1 addition & 0 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ As of now, Mantis has all of the core features needed to be used in almost any s
- JSON Path support
- Support for a Wiremock's `Scenario`-like feature
- Simulate production environments more accurately by defining delays on responses
- Opentelemetry traces support
- More to come
42 changes: 33 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,35 @@ module github.com/dubonzi/mantis
go 1.22

require (
github.com/americanas-go/config v1.8.5
github.com/americanas-go/log v1.8.9
github.com/gofiber/fiber/v2 v2.52.1
github.com/americanas-go/config v1.8.6
github.com/americanas-go/log v1.8.10
github.com/gofiber/contrib/otelfiber v1.0.10
github.com/gofiber/fiber/v2 v2.52.2
github.com/google/uuid v1.6.0
github.com/ohler55/ojg v1.21.4
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
go.uber.org/fx v1.20.1
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0
go.opentelemetry.io/otel/sdk v1.24.0
go.opentelemetry.io/otel/sdk/metric v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
go.uber.org/fx v1.21.0
)

require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gobeam/stringy v0.0.6 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/knadh/koanf v1.5.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
Expand All @@ -28,15 +41,26 @@ require (
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/fasthttp v1.52.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
go.opentelemetry.io/contrib v1.24.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.uber.org/dig v1.17.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/sys v0.16.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/grpc v1.61.1 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading