Skip to content

Flamingo in Production

The benefit of Go is that you build/compile a standalone binary without any external dependencies.

We recommend that you do so in a proper continuous integration pipeline that runs all your tests before with go test -race -vet=all ./...

Deployment Artifact

Make sure to bundle the templates and config files. For example in a tarball/zipball or a Docker image

Docker

Check the file example/dist/Dockerfile for an example Dockerfile that you can use in your application:

# Example Dockerfile for Flamingo/Go based Projects

# Builder
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache ca-certificates tzdata git && update-ca-certificates
COPY . /app
RUN cd /app && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .

# Final image
FROM scratch

# add timezone data and ssl root certificates
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# add artifacts
#ADD config /config

# add binary
COPY --from=builder /app/app /app

ENTRYPOINT ["/app"]
CMD ["serve"]

Running Flamingo

  • Run it behind a Load Balancer like Nginx or a Kubernetes Ingress

Observability

Logging

Logging is an essential part of any application, as it helps in tracking events, debugging issues, and monitoring the application’s behavior. The Flamingo Web Framework provides a simple and efficient way to implement logging in your web applications.

Basic usage

To start using the logger in Flamingo, you need to inject the flamingo.Logger interface.

package example

import (
    "flamingo.me/flamingo/v3/framework/flamingo"
)

type (
    MyStruct struct{
        logger flamingo.Logger
    }
)

func (s *MyStruct) Inject(logger flamingo.Logger) *MyStruct {
    s.logger = logger
    return s
}

func (s *MyStruct) SomeFunc() {
    s.logger.Debug("This is a debug message")
    s.logger.Info("This is an info message")
    s.logger.Warn("This is a warning message")
    s.logger.Error("This is an error message")
    s.logger.Fatal("This is a fatal message")
}

Trace logging

Flamingo also supports a Trace log level, which is below Debug and intended to provide very detailed logging information. This can be useful for deep debugging and tracing the flow of your application. However, the Trace log level is not enabled by default and requires a build tag to be activated.

This will add the Trace functions to the flamingo.Logger interface.

To enable the Trace log level, you need to compile your application with the tracelog build tag:

go build -tags tracelog

Logging with Context and additional fields

Flamingo's logger also supports logging with context and additional fields, which is useful for adding extra metadata to your log entries:

func (s *MyStruct) someFunction(ctx context.Context) {
    s.logger.WithField(flamingo.LogKeyCategory, "SomeCategory").Info("This is an info message with context")
    s.logger.WithContext(ctx).Info("This is an info message with context")
}

You can chain multiple With functions together. There are a lot of prepared constants for common log keys.

Default and custom logger implementations

The standard implementation for the Logger interface is the zap Logger. It is automatically bound to the interface by Flamingo.

Read more about the ZAP Logger in Flamingo

To use another implementation, you can specify the ApplicationOption WithCustomLogger and pass a Flamingo module:

package main

import (
    "flamingo.me/flamingo/v3"
)

func main() {
    flamingo.App([]dingo.Module{
        // your modules
    }, flamingo.WithCustomLogger(new(MyLogModule)))
}

This Flamingo module must at least bind an implementation to the flamingo.Logger interface.

An alternative implementation available in the core is silentzap. Silentzap wraps the zap logger and only logs when an error happens, but then all levels are in the same context/trace.

OpenTelemetry

For metrics support and to push tracing information to Jaeger/Zipkin Flamingo uses OpenTelemetry. Read more about OpenTelemetry