11package mqtt
22
33import (
4+ "context"
45 "crypto/tls"
56 "crypto/x509"
67 "fmt"
@@ -10,14 +11,15 @@ import (
1011 "time"
1112
1213 paho "github.com/eclipse/paho.mqtt.golang"
14+ "github.com/grafana/grafana-plugin-sdk-go/backend"
1315 "github.com/grafana/grafana-plugin-sdk-go/backend/log"
1416)
1517
1618type Client interface {
1719 GetTopic (string ) (* Topic , bool )
1820 IsConnected () bool
19- Subscribe (string ) * Topic
20- Unsubscribe (string )
21+ Subscribe (string , log. Logger ) * Topic
22+ Unsubscribe (string , log. Logger )
2123 Dispose ()
2224}
2325
@@ -37,7 +39,8 @@ type client struct {
3739 topics TopicMap
3840}
3941
40- func NewClient (o Options ) (Client , error ) {
42+ func NewClient (ctx context.Context , o Options ) (Client , error ) {
43+ logger := log .DefaultLogger .FromContext (ctx )
4144 opts := paho .NewClientOptions ()
4245
4346 opts .AddBroker (o .URI )
@@ -63,7 +66,7 @@ func NewClient(o Options) (Client, error) {
6366 if o .TLSClientCert != "" || o .TLSClientKey != "" {
6467 cert , err := tls .X509KeyPair ([]byte (o .TLSClientCert ), []byte (o .TLSClientKey ))
6568 if err != nil {
66- return nil , fmt . Errorf ("failed to setup TLSClientCert: %w" , err )
69+ return nil , backend . DownstreamErrorf ("failed to setup TLSClientCert: %w" , err )
6770 }
6871
6972 tlsConfig .Certificates = append (tlsConfig .Certificates , cert )
@@ -82,17 +85,17 @@ func NewClient(o Options) (Client, error) {
8285 opts .SetCleanSession (false )
8386 opts .SetMaxReconnectInterval (10 * time .Second )
8487 opts .SetConnectionLostHandler (func (c paho.Client , err error ) {
85- log . DefaultLogger . Error ("MQTT Connection lost" , "error" , err )
88+ logger . Warn ("MQTT Connection lost" , "error" , err )
8689 })
8790 opts .SetReconnectingHandler (func (c paho.Client , options * paho.ClientOptions ) {
88- log . DefaultLogger .Debug ("MQTT Reconnecting" )
91+ logger .Debug ("MQTT Reconnecting" )
8992 })
9093
91- log . DefaultLogger .Info ("MQTT Connecting" , "clientID" , clientID )
94+ logger .Info ("MQTT Connecting" , "clientID" , clientID )
9295
9396 pahoClient := paho .NewClient (opts )
9497 if token := pahoClient .Connect (); token .Wait () && token .Error () != nil {
95- return nil , fmt . Errorf ("error connecting to MQTT broker: %s" , token .Error ())
98+ return nil , backend . DownstreamErrorf ("error connecting to MQTT broker: %s" , token .Error ())
9699 }
97100
98101 return & client {
@@ -117,20 +120,20 @@ func (c *client) GetTopic(reqPath string) (*Topic, bool) {
117120 return c .topics .Load (reqPath )
118121}
119122
120- func (c * client ) Subscribe (reqPath string ) * Topic {
123+ func (c * client ) Subscribe (reqPath string , logger log. Logger ) * Topic {
121124 // Check if there's already a topic with this exact key (reqPath)
122125 if existingTopic , ok := c .topics .Load (reqPath ); ok {
123126 return existingTopic
124127 }
125128
126129 chunks := strings .Split (reqPath , "/" )
127130 if len (chunks ) < 2 {
128- log . DefaultLogger .Error ("Invalid path" , "path" , reqPath )
131+ logger .Error ("Invalid path" , "path" , reqPath )
129132 return nil
130133 }
131134 interval , err := time .ParseDuration (chunks [0 ])
132135 if err != nil {
133- log . DefaultLogger .Error ("Invalid interval" , "path" , reqPath , "interval" , chunks [0 ])
136+ logger .Error ("Invalid interval" , "path" , reqPath , "interval" , chunks [0 ])
134137 return nil
135138 }
136139
@@ -145,27 +148,27 @@ func (c *client) Subscribe(reqPath string) *Topic {
145148 Interval : interval ,
146149 }
147150
148- topic , err := decodeTopic (t .Path )
151+ topic , err := decodeTopic (t .Path , logger )
149152 if err != nil {
150- log . DefaultLogger . Error ("Error decoding MQTT topic name" , "encodedTopic" , t .Path , "error" , err )
153+ logger . Error ("Error decoding MQTT topic name" , "encodedTopic" , t .Path , "error" , backend . DownstreamError ( err ) )
151154 return nil
152155 }
153156
154- log . DefaultLogger .Debug ("Subscribing to MQTT topic" , "topic" , topic )
157+ logger .Debug ("Subscribing to MQTT topic" , "topic" , topic )
155158
156159 if token := c .client .Subscribe (topic , 0 , func (_ paho.Client , m paho.Message ) {
157160 // by wrapping HandleMessage we can directly get the correct topicPath for the incoming topic
158161 // and don't need to regex it against + and #.
159162 c .HandleMessage (topicPath , []byte (m .Payload ()))
160163 }); token .Wait () && token .Error () != nil {
161- log . DefaultLogger . Error ("Error subscribing to MQTT topic" , "topic" , topic , "error" , token .Error ())
164+ logger . Error ("Error subscribing to MQTT topic" , "topic" , topic , "error" , backend . DownstreamError ( token .Error () ))
162165 }
163166 // Store the topic using reqPath as the key (which includes streaming key)
164167 c .topics .Map .Store (reqPath , t )
165168 return t
166169}
167170
168- func (c * client ) Unsubscribe (reqPath string ) {
171+ func (c * client ) Unsubscribe (reqPath string , logger log. Logger ) {
169172 t , ok := c .GetTopic (reqPath )
170173 if ! ok {
171174 return
@@ -178,16 +181,16 @@ func (c *client) Unsubscribe(reqPath string) {
178181 return
179182 }
180183
181- log . DefaultLogger .Debug ("Unsubscribing from MQTT topic" , "topic" , t .Path )
184+ logger .Debug ("Unsubscribing from MQTT topic" , "topic" , t .Path )
182185
183- topic , err := decodeTopic (t .Path )
186+ topic , err := decodeTopic (t .Path , logger )
184187 if err != nil {
185- log . DefaultLogger . Error ("Error decoding MQTT topic name" , "encodedTopic" , t .Path , "error" , err )
188+ logger . Error ("Error decoding MQTT topic name" , "encodedTopic" , t .Path , "error" , backend . DownstreamError ( err ) )
186189 return
187190 }
188191
189192 if token := c .client .Unsubscribe (topic ); token .Wait () && token .Error () != nil {
190- log . DefaultLogger . Error ("Error unsubscribing from MQTT topic" , "topic" , t .Path , "error" , token .Error ())
193+ logger . Error ("Error unsubscribing from MQTT topic" , "topic" , t .Path , "error" , backend . DownstreamError ( token .Error () ))
191194 }
192195}
193196
0 commit comments