2022-05-25 22:48:59 +08:00
|
|
|
//go:generate ../../../tools/readme_config_includer/generator
|
2015-10-04 21:52:29 +08:00
|
|
|
package mqtt
|
|
|
|
|
|
|
|
|
|
import (
|
2022-05-25 22:48:59 +08:00
|
|
|
_ "embed"
|
2015-10-04 21:52:29 +08:00
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
2018-01-23 03:15:13 +08:00
|
|
|
"time"
|
2015-10-04 21:52:29 +08:00
|
|
|
|
2019-02-12 09:25:25 +08:00
|
|
|
paho "github.com/eclipse/paho.mqtt.golang"
|
2021-11-25 03:40:25 +08:00
|
|
|
|
2016-01-28 07:15:14 +08:00
|
|
|
"github.com/influxdata/telegraf"
|
2021-04-10 01:15:04 +08:00
|
|
|
"github.com/influxdata/telegraf/config"
|
2016-01-21 02:57:35 +08:00
|
|
|
"github.com/influxdata/telegraf/internal"
|
2020-06-26 02:44:22 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/common/tls"
|
2016-01-21 02:57:35 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/outputs"
|
2016-02-11 06:50:07 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/serializers"
|
2015-10-04 21:52:29 +08:00
|
|
|
)
|
|
|
|
|
|
2022-05-27 21:13:47 +08:00
|
|
|
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the sampleConfig data.
|
2022-05-25 22:48:59 +08:00
|
|
|
//go:embed sample.conf
|
|
|
|
|
var sampleConfig string
|
|
|
|
|
|
2021-10-01 23:10:30 +08:00
|
|
|
const (
|
|
|
|
|
defaultKeepAlive = 0
|
|
|
|
|
)
|
|
|
|
|
|
2015-10-04 21:52:29 +08:00
|
|
|
type MQTT struct {
|
|
|
|
|
Servers []string `toml:"servers"`
|
|
|
|
|
Username string
|
|
|
|
|
Password string
|
|
|
|
|
Database string
|
2021-04-10 01:15:04 +08:00
|
|
|
Timeout config.Duration
|
2015-10-04 21:52:29 +08:00
|
|
|
TopicPrefix string
|
2016-11-24 23:11:24 +08:00
|
|
|
QoS int `toml:"qos"`
|
|
|
|
|
ClientID string `toml:"client_id"`
|
2018-05-05 07:33:23 +08:00
|
|
|
tls.ClientConfig
|
2021-11-25 03:40:25 +08:00
|
|
|
BatchMessage bool `toml:"batch"`
|
|
|
|
|
Retain bool `toml:"retain"`
|
|
|
|
|
KeepAlive int64 `toml:"keep_alive"`
|
|
|
|
|
Log telegraf.Logger `toml:"-"`
|
2016-02-04 03:59:34 +08:00
|
|
|
|
2016-03-31 01:54:01 +08:00
|
|
|
client paho.Client
|
2016-02-04 03:59:34 +08:00
|
|
|
opts *paho.ClientOptions
|
|
|
|
|
|
2016-02-11 06:50:07 +08:00
|
|
|
serializer serializers.Serializer
|
|
|
|
|
|
2015-10-04 21:52:29 +08:00
|
|
|
sync.Mutex
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 22:48:59 +08:00
|
|
|
func (*MQTT) SampleConfig() string {
|
|
|
|
|
return sampleConfig
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-04 21:52:29 +08:00
|
|
|
func (m *MQTT) Connect() error {
|
|
|
|
|
var err 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
|
|
|
|
2016-02-04 03:59:34 +08:00
|
|
|
m.opts, err = m.createOpts()
|
2015-10-04 21:52:29 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-04 03:59:34 +08:00
|
|
|
m.client = paho.NewClient(m.opts)
|
|
|
|
|
if token := m.client.Connect(); token.Wait() && token.Error() != nil {
|
2015-10-04 21:52:29 +08:00
|
|
|
return token.Error()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-11 06:50:07 +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 {
|
2016-02-04 03:59:34 +08:00
|
|
|
if m.client.IsConnected() {
|
|
|
|
|
m.client.Disconnect(20)
|
2015-10-04 21:52:29 +08:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 07:15:14 +08:00
|
|
|
func (m *MQTT) Write(metrics []telegraf.Metric) error {
|
2015-10-04 21:52:29 +08:00
|
|
|
m.Lock()
|
|
|
|
|
defer m.Unlock()
|
2016-01-28 07:15:14 +08:00
|
|
|
if len(metrics) == 0 {
|
2015-10-04 21:52:29 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
2016-01-28 07:15:14 +08:00
|
|
|
hostname, ok := metrics[0].Tags()["host"]
|
2015-10-05 10:07:41 +08:00
|
|
|
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)
|
|
|
|
|
|
2016-02-11 06:50:07 +08:00
|
|
|
for _, metric := range metrics {
|
2015-10-04 21:52:29 +08:00
|
|
|
var t []string
|
|
|
|
|
if m.TopicPrefix != "" {
|
|
|
|
|
t = append(t, m.TopicPrefix)
|
|
|
|
|
}
|
2016-02-04 03:59:34 +08:00
|
|
|
if hostname != "" {
|
|
|
|
|
t = append(t, hostname)
|
2015-10-05 09:43:46 +08:00
|
|
|
}
|
2015-10-17 06:13:32 +08:00
|
|
|
|
2016-02-11 06:50:07 +08:00
|
|
|
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 {
|
2021-11-25 03:40:25 +08:00
|
|
|
m.Log.Debugf("Could not serialize metric: %v", err)
|
2019-06-04 08:34:48 +08:00
|
|
|
continue
|
2018-05-19 09:55:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = m.publish(topic, buf)
|
|
|
|
|
if err != nil {
|
2021-11-25 03:40:25 +08:00
|
|
|
return fmt.Errorf("could not write to MQTT server, %s", err)
|
2018-05-19 09:55:02 +08:00
|
|
|
}
|
2016-02-11 06:50:07 +08:00
|
|
|
}
|
2018-05-19 09:55:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for key := range metricsmap {
|
|
|
|
|
buf, err := m.serializer.SerializeBatch(metricsmap[key])
|
2016-02-11 06:50:07 +08:00
|
|
|
|
2016-11-22 20:51:57 +08:00
|
|
|
if err != nil {
|
2018-05-19 09:55:02 +08:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
publisherr := m.publish(key, buf)
|
|
|
|
|
if publisherr != nil {
|
2021-11-25 03:40:25 +08:00
|
|
|
return fmt.Errorf("could not write to MQTT server, %s", publisherr)
|
2015-10-04 21:52:29 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-22 20:51:57 +08:00
|
|
|
func (m *MQTT) publish(topic string, body []byte) error {
|
2019-02-12 09:22:31 +08:00
|
|
|
token := m.client.Publish(topic, byte(m.QoS), m.Retain, body)
|
2021-04-10 01:15:04 +08:00
|
|
|
token.WaitTimeout(time.Duration(m.Timeout))
|
2015-10-04 21:52:29 +08:00
|
|
|
if token.Error() != nil {
|
|
|
|
|
return token.Error()
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-04 03:59:34 +08:00
|
|
|
func (m *MQTT) createOpts() (*paho.ClientOptions, error) {
|
2015-10-04 21:52:29 +08:00
|
|
|
opts := paho.NewClientOptions()
|
2021-10-01 23:10:30 +08:00
|
|
|
opts.KeepAlive = m.KeepAlive
|
2015-10-04 21:52:29 +08:00
|
|
|
|
2021-04-10 01:15:04 +08:00
|
|
|
if m.Timeout < config.Duration(time.Second) {
|
|
|
|
|
m.Timeout = config.Duration(5 * time.Second)
|
2018-01-23 03:15:13 +08:00
|
|
|
}
|
2021-04-10 01:15:04 +08:00
|
|
|
opts.WriteTimeout = time.Duration(m.Timeout)
|
2018-01-23 03:15:13 +08:00
|
|
|
|
2016-11-24 23:11:24 +08:00
|
|
|
if m.ClientID != "" {
|
|
|
|
|
opts.SetClientID(m.ClientID)
|
|
|
|
|
} else {
|
|
|
|
|
opts.SetClientID("Telegraf-Output-" + internal.RandomString(5))
|
|
|
|
|
}
|
2016-02-04 03:59:34 +08:00
|
|
|
|
2018-05-05 07:33:23 +08:00
|
|
|
tlsCfg, err := m.ClientConfig.TLSConfig()
|
2016-02-04 03:59:34 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2015-10-04 21:52:29 +08:00
|
|
|
|
|
|
|
|
scheme := "tcp"
|
2016-02-04 03:59:34 +08:00
|
|
|
if tlsCfg != nil {
|
2015-10-04 21:52:29 +08:00
|
|
|
scheme = "ssl"
|
2016-02-04 03:59:34 +08:00
|
|
|
opts.SetTLSConfig(tlsCfg)
|
2015-10-04 21:52:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
user := m.Username
|
2016-03-03 21:14:50 +08:00
|
|
|
if user != "" {
|
2015-10-04 21:52:29 +08:00
|
|
|
opts.SetUsername(user)
|
|
|
|
|
}
|
|
|
|
|
password := m.Password
|
|
|
|
|
if password != "" {
|
|
|
|
|
opts.SetPassword(password)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(m.Servers) == 0 {
|
2020-05-16 06:43:32 +08:00
|
|
|
return opts, fmt.Errorf("could not get host informations")
|
2015-10-04 21:52:29 +08:00
|
|
|
}
|
|
|
|
|
for _, host := range m.Servers {
|
|
|
|
|
server := fmt.Sprintf("%s://%s", scheme, host)
|
|
|
|
|
|
|
|
|
|
opts.AddBroker(server)
|
|
|
|
|
}
|
|
|
|
|
opts.SetAutoReconnect(true)
|
|
|
|
|
return opts, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init() {
|
2016-01-28 05:21:36 +08:00
|
|
|
outputs.Add("mqtt", func() telegraf.Output {
|
2021-10-01 23:10:30 +08:00
|
|
|
return &MQTT{
|
|
|
|
|
KeepAlive: defaultKeepAlive,
|
|
|
|
|
}
|
2015-10-04 21:52:29 +08:00
|
|
|
})
|
|
|
|
|
}
|