Initializing common things to multiple modules

Hi,
I have a couple of custom modules for observability, and they need to bootstrap the same components internally. For example, I want them to share a single OTEL MeterProvider, which I want to bootstrap only once, using my custom settings. How can I achieve this in a Caddy way?

From what I understand, the order of Provision calls isn’t guaranteed, so I can’t ensure that the observability module is bootstrapped before the others. The only solution I’ve come up with is using a package-level singleton within the module and then loading that module (ctx.LoadModule) in every dependent module, so they’re not reliant on the order of either init or Provision.

You can use a UsagePool to store state that is shared between modules, even across config reloads.

Or, you can use an App module and call ctx.App() in other modules that need it.

1 Like

Thanks, seems worked! I’ve came up with the following:

A module N, that uses OTEL Meter Provider, etc:

func (h *HandlerN) Provision(ctx caddy.Context) error {
    ...
    if _, err := ctx.App("my.module.observability"); err != nil {
        return fmt.Errorf("failed to initialize observability app: %w", err)
    }
    ...

    return nil
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
    otel.GetMeterProvider()...

    return next.ServeHTTP(w, r)
}

A module, that initializes everything

func (o *Observability) Start() error {
    startCustomTracer()
    initOtelMeterProvider()
    return nil
}

func (o *Observability) Stop() error {
    shutdownCustomTracer()
    shutdownOtelMeterProvider()
}

The module IDs of Caddy apps consist of 1 part, so it cannot be like this.

You can change the module ID to observability or anything that does not consist of dots between its parts.

2 Likes

what about name conflicts? in case Caddy introduces observability app or somebody else? Can I use prefixes, perhaps something like my_company_observability?

1 Like

Well, if your app is specific to your company or internal-use, you should name it as such. In theory, an app named “observability” should be the one app to do observability, kind of like how the app named “http” is the one to serve HTTP.

It’s okay if there is a conflict globally, just not in any particular build of Caddy.

1 Like