2022-05-24 21:49:47 +08:00
|
|
|
//go:generate ../../../tools/readme_config_includer/generator
|
2017-08-03 08:58:26 +08:00
|
|
|
package zipkin
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2022-05-24 21:49:47 +08:00
|
|
|
_ "embed"
|
2017-08-03 08:58:26 +08:00
|
|
|
"fmt"
|
|
|
|
|
"net"
|
|
|
|
|
"net/http"
|
|
|
|
|
"strconv"
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
2021-11-18 22:22:43 +08:00
|
|
|
|
2017-08-03 08:58:26 +08:00
|
|
|
"github.com/influxdata/telegraf"
|
|
|
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
2017-08-22 08:24:54 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/inputs/zipkin/trace"
|
2017-08-03 08:58:26 +08:00
|
|
|
)
|
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
//go:embed sample.conf
|
|
|
|
|
var sampleConfig string
|
|
|
|
|
|
2017-08-03 08:58:26 +08:00
|
|
|
const (
|
|
|
|
|
// DefaultPort is the default port zipkin listens on, which zipkin implementations
|
|
|
|
|
// expect.
|
|
|
|
|
DefaultPort = 9411
|
|
|
|
|
|
|
|
|
|
// DefaultRoute is the default route zipkin uses, and zipkin implementations
|
|
|
|
|
// expect.
|
|
|
|
|
DefaultRoute = "/api/v1/spans"
|
|
|
|
|
|
|
|
|
|
// DefaultShutdownTimeout is the max amount of time telegraf will wait
|
|
|
|
|
// for the plugin to shutdown
|
|
|
|
|
DefaultShutdownTimeout = 5
|
|
|
|
|
)
|
|
|
|
|
|
2018-04-19 07:14:06 +08:00
|
|
|
var (
|
|
|
|
|
// DefaultNetwork is the network to listen on; use only in tests.
|
|
|
|
|
DefaultNetwork = "tcp"
|
|
|
|
|
)
|
|
|
|
|
|
2017-08-03 08:58:26 +08:00
|
|
|
// Recorder represents a type which can record zipkin trace data as well as
|
|
|
|
|
// any accompanying errors, and process that data.
|
|
|
|
|
type Recorder interface {
|
2017-08-22 08:24:54 +08:00
|
|
|
Record(trace.Trace) error
|
2017-08-03 08:58:26 +08:00
|
|
|
Error(error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handler represents a type which can register itself with a router for
|
|
|
|
|
// http routing, and a Recorder for trace data collection.
|
|
|
|
|
type Handler interface {
|
|
|
|
|
Register(router *mux.Router, recorder Recorder) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Zipkin is a telegraf configuration structure for the zipkin input plugin,
|
|
|
|
|
// but it also contains fields for the management of a separate, concurrent
|
|
|
|
|
// zipkin http server
|
|
|
|
|
type Zipkin struct {
|
|
|
|
|
ServiceAddress string
|
|
|
|
|
Port int
|
|
|
|
|
Path string
|
|
|
|
|
|
2019-09-24 06:39:50 +08:00
|
|
|
Log telegraf.Logger
|
|
|
|
|
|
2017-08-03 08:58:26 +08:00
|
|
|
address string
|
|
|
|
|
handler Handler
|
|
|
|
|
server *http.Server
|
|
|
|
|
waitGroup *sync.WaitGroup
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
func (*Zipkin) SampleConfig() string {
|
|
|
|
|
return sampleConfig
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 08:58:26 +08:00
|
|
|
// Gather is empty for the zipkin plugin; all gathering is done through
|
|
|
|
|
// the separate goroutine launched in (*Zipkin).Start()
|
2021-03-23 01:21:36 +08:00
|
|
|
func (z *Zipkin) Gather(_ telegraf.Accumulator) error { return nil }
|
2017-08-03 08:58:26 +08:00
|
|
|
|
|
|
|
|
// Start launches a separate goroutine for collecting zipkin client http requests,
|
|
|
|
|
// passing in a telegraf.Accumulator such that data can be collected.
|
|
|
|
|
func (z *Zipkin) Start(acc telegraf.Accumulator) error {
|
|
|
|
|
z.handler = NewSpanHandler(z.Path)
|
|
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
z.waitGroup = &wg
|
|
|
|
|
|
|
|
|
|
router := mux.NewRouter()
|
|
|
|
|
converter := NewLineProtocolConverter(acc)
|
2017-08-22 08:24:54 +08:00
|
|
|
if err := z.handler.Register(router, converter); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2017-08-03 08:58:26 +08:00
|
|
|
|
|
|
|
|
z.server = &http.Server{
|
|
|
|
|
Handler: router,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addr := ":" + strconv.Itoa(z.Port)
|
2018-04-19 07:14:06 +08:00
|
|
|
ln, err := net.Listen(DefaultNetwork, addr)
|
2017-08-03 08:58:26 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
z.address = ln.Addr().String()
|
2019-09-24 06:39:50 +08:00
|
|
|
z.Log.Infof("Started the zipkin listener on %s", z.address)
|
2017-08-03 08:58:26 +08:00
|
|
|
|
2021-11-18 22:22:43 +08:00
|
|
|
wg.Add(1)
|
2017-08-03 08:58:26 +08:00
|
|
|
go func() {
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
|
|
z.Listen(ln, acc)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stop shuts the internal http server down with via context.Context
|
|
|
|
|
func (z *Zipkin) Stop() {
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), DefaultShutdownTimeout)
|
|
|
|
|
|
|
|
|
|
defer z.waitGroup.Wait()
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
2023-02-08 00:06:12 +08:00
|
|
|
z.server.Shutdown(ctx) //nolint:errcheck,revive // Ignore the returned error as we cannot do anything about it anyway
|
2017-08-03 08:58:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Listen creates an http server on the zipkin instance it is called with, and
|
|
|
|
|
// serves http until it is stopped by Zipkin's (*Zipkin).Stop() method.
|
|
|
|
|
func (z *Zipkin) Listen(ln net.Listener, acc telegraf.Accumulator) {
|
|
|
|
|
if err := z.server.Serve(ln); err != nil {
|
|
|
|
|
// Because of the clean shutdown in `(*Zipkin).Stop()`
|
|
|
|
|
// We're expecting a server closed error at some point
|
|
|
|
|
// So we don't want to display it as an error.
|
|
|
|
|
// This interferes with telegraf's internal data collection,
|
|
|
|
|
// by making it appear as if a serious error occurred.
|
|
|
|
|
if err != http.ErrServerClosed {
|
2021-11-18 22:22:43 +08:00
|
|
|
acc.AddError(fmt.Errorf("error listening: %v", err))
|
2017-08-03 08:58:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
inputs.Add("zipkin", func() telegraf.Input {
|
|
|
|
|
return &Zipkin{
|
|
|
|
|
Path: DefaultRoute,
|
|
|
|
|
Port: DefaultPort,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|