maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package openmetrics
 20
 21import (
 22	"errors"
 23	"fmt"
 24	"net"
 25	"net/http"
 26	"sync"
 27
 28	"github.com/foxcpp/maddy/framework/config"
 29	"github.com/foxcpp/maddy/framework/log"
 30	"github.com/foxcpp/maddy/framework/module"
 31	"github.com/prometheus/client_golang/prometheus/promhttp"
 32)
 33
 34const modName = "openmetrics"
 35
 36type Endpoint struct {
 37	addrs  []string
 38	logger log.Logger
 39
 40	listenersWg sync.WaitGroup
 41	serv        http.Server
 42	mux         *http.ServeMux
 43}
 44
 45func New(_ string, args []string) (module.Module, error) {
 46	return &Endpoint{
 47		addrs:  args,
 48		logger: log.Logger{Name: modName, Debug: log.DefaultLogger.Debug},
 49	}, nil
 50}
 51
 52func (e *Endpoint) Init(cfg *config.Map) error {
 53	cfg.Bool("debug", false, false, &e.logger.Debug)
 54	if _, err := cfg.Process(); err != nil {
 55		return err
 56	}
 57
 58	e.mux = http.NewServeMux()
 59	e.mux.Handle("/metrics", promhttp.Handler())
 60	e.serv.Handler = e.mux
 61
 62	for _, a := range e.addrs {
 63		endp, err := config.ParseEndpoint(a)
 64		if err != nil {
 65			return fmt.Errorf("%s: malformed endpoint: %v", modName, err)
 66		}
 67		if endp.IsTLS() {
 68			return fmt.Errorf("%s: TLS is not supported yet", modName)
 69		}
 70		l, err := net.Listen(endp.Network(), endp.Address())
 71		if err != nil {
 72			return fmt.Errorf("%s: %v", modName, err)
 73		}
 74
 75		e.listenersWg.Add(1)
 76		go func() {
 77			e.logger.Println("listening on", endp.String())
 78			err := e.serv.Serve(l)
 79			if err != nil && !errors.Is(err, http.ErrServerClosed) {
 80				e.logger.Error("serve failed", err, "endpoint", a)
 81			}
 82			e.listenersWg.Done()
 83		}()
 84	}
 85
 86	return nil
 87}
 88
 89func (e *Endpoint) Name() string {
 90	return modName
 91}
 92
 93func (e *Endpoint) InstanceName() string {
 94	return ""
 95}
 96
 97func (e *Endpoint) Close() error {
 98	if err := e.serv.Close(); err != nil {
 99		return err
100	}
101	e.listenersWg.Wait()
102	return nil
103}
104
105func init() {
106	module.RegisterEndpoint(modName, New)
107}