telegraf/plugins/outputs/mqtt/mqtt.go

167 lines
3.6 KiB
Go
Raw Normal View History

//go:generate ../../../tools/readme_config_includer/generator
2015-10-04 21:52:29 +08:00
package mqtt
import (
// Blank import to support go:embed compile directive
_ "embed"
2015-10-04 21:52:29 +08:00
"fmt"
"net/url"
2015-10-04 21:52:29 +08:00
"strings"
"sync"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/common/tls"
2016-01-21 02:57:35 +08:00
"github.com/influxdata/telegraf/plugins/outputs"
"github.com/influxdata/telegraf/plugins/serializers"
2015-10-04 21:52:29 +08:00
)
//go:embed sample.conf
var sampleConfig string
const (
defaultKeepAlive = 30
)
2015-10-04 21:52:29 +08:00
type MQTT struct {
Servers []string `toml:"servers"`
Protocol string `toml:"protocol"`
Username string `toml:"username"`
Password string `toml:"password"`
2015-10-04 21:52:29 +08:00
Database string
Timeout config.Duration `toml:"timeout"`
TopicPrefix string `toml:"topic_prefix"`
QoS int `toml:"qos"`
ClientID string `toml:"client_id"`
2018-05-05 07:33:23 +08:00
tls.ClientConfig
BatchMessage bool `toml:"batch"`
Retain bool `toml:"retain"`
KeepAlive int64 `toml:"keep_alive"`
Log telegraf.Logger `toml:"-"`
client Client
serializer serializers.Serializer
2015-10-04 21:52:29 +08:00
sync.Mutex
}
// Client is a protocol neutral MQTT client for connecting,
// disconnecting, and publishing data to a topic.
// The protocol specific clients must implement this interface
type Client interface {
Connect() error
Publish(topic string, data []byte) error
Close() error
}
func (*MQTT) SampleConfig() string {
return sampleConfig
}
2015-10-04 21:52:29 +08:00
func (m *MQTT) Connect() error {
m.Lock()
defer m.Unlock()
2016-02-10 06:03:46 +08:00
if m.QoS > 2 || m.QoS < 0 {
return fmt.Errorf("MQTT Output, invalid QoS value: %d", m.QoS)
}
2015-10-04 21:52:29 +08:00
switch m.Protocol {
case "", "3.1.1":
m.client = newMQTTv311Client(m)
case "5":
m.client = newMQTTv5Client(m)
default:
return fmt.Errorf("unsuported protocol %q: must be \"3.1.1\" or \"5\"", m.Protocol)
2015-10-04 21:52:29 +08:00
}
return m.client.Connect()
2015-10-04 21:52:29 +08:00
}
func (m *MQTT) SetSerializer(serializer serializers.Serializer) {
m.serializer = serializer
}
2015-10-04 21:52:29 +08:00
func (m *MQTT) Close() error {
return m.client.Close()
2015-10-04 21:52:29 +08:00
}
func (m *MQTT) Write(metrics []telegraf.Metric) error {
2015-10-04 21:52:29 +08:00
m.Lock()
defer m.Unlock()
if len(metrics) == 0 {
2015-10-04 21:52:29 +08:00
return nil
}
hostname, ok := metrics[0].Tags()["host"]
if !ok {
hostname = ""
}
2015-10-04 21:52:29 +08:00
2018-05-19 09:55:02 +08:00
metricsmap := make(map[string][]telegraf.Metric)
for _, metric := range metrics {
2015-10-04 21:52:29 +08:00
var t []string
if m.TopicPrefix != "" {
t = append(t, m.TopicPrefix)
}
if hostname != "" {
t = append(t, hostname)
}
t = append(t, metric.Name())
2015-10-04 21:52:29 +08:00
topic := strings.Join(t, "/")
2018-05-19 09:55:02 +08:00
if m.BatchMessage {
metricsmap[topic] = append(metricsmap[topic], metric)
} else {
buf, err := m.serializer.Serialize(metric)
if err != nil {
m.Log.Debugf("Could not serialize metric: %v", err)
continue
2018-05-19 09:55:02 +08:00
}
err = m.client.Publish(topic, buf)
2018-05-19 09:55:02 +08:00
if err != nil {
return fmt.Errorf("could not write to MQTT server, %s", err)
2018-05-19 09:55:02 +08:00
}
}
2018-05-19 09:55:02 +08:00
}
for key := range metricsmap {
buf, err := m.serializer.SerializeBatch(metricsmap[key])
if err != nil {
2018-05-19 09:55:02 +08:00
return err
}
err = m.client.Publish(key, buf)
if err != nil {
return fmt.Errorf("could not write to MQTT server, %s", err)
2015-10-04 21:52:29 +08:00
}
}
return nil
}
func parseServers(servers []string) ([]*url.URL, error) {
urls := make([]*url.URL, 0, len(servers))
for _, svr := range servers {
if !strings.Contains(svr, "://") {
urls = append(urls, &url.URL{Scheme: "tcp", Host: svr})
} else {
u, err := url.Parse(svr)
if err != nil {
return nil, err
}
urls = append(urls, u)
}
2015-10-04 21:52:29 +08:00
}
return urls, nil
2015-10-04 21:52:29 +08:00
}
func init() {
outputs.Add("mqtt", func() telegraf.Output {
return &MQTT{
KeepAlive: defaultKeepAlive,
}
2015-10-04 21:52:29 +08:00
})
}