master
go 215 lines 5.88 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package netdataapi
4
5 import (
6 "bytes"
7 "fmt"
8 "io"
9 "sort"
10 "strconv"
11 )
12
13 // API implements Netdata external plugins API.
14 // See: https://learn.netdata.cloud/docs/agent/plugins.d#the-output-of-the-plugin
15 type API struct {
16 io.Writer
17 }
18
19 const quotes = "' '"
20
21 var (
22 end = []byte("END\n\n")
23 clabelCommit = []byte("CLABEL_COMMIT\n")
24 newLine = []byte("\n")
25 )
26
27 // New creates a new API instance for interacting with Netdata.
28 // Panics if the provided writer is nil.
29 func New(w io.Writer) *API {
30 if w == nil {
31 panic("writer cannot be nil")
32 }
33 return &API{w}
34 }
35
36 // CHART creates or updates a chart.
37 func (a *API) CHART(opts ChartOpts) {
38 _, _ = a.Write([]byte("CHART " + "'" +
39 opts.TypeID + "." + opts.ID + quotes +
40 opts.Name + quotes +
41 opts.Title + quotes +
42 opts.Units + quotes +
43 opts.Family + quotes +
44 opts.Context + quotes +
45 opts.ChartType + quotes +
46 strconv.Itoa(opts.Priority) + quotes +
47 strconv.Itoa(opts.UpdateEvery) + quotes +
48 opts.Options + quotes +
49 opts.Plugin + quotes +
50 opts.Module + "'\n"))
51 }
52
53 // DIMENSION adds or updates a dimension to the most recently created chart.
54 func (a *API) DIMENSION(opts DimensionOpts) {
55 _, _ = a.Write([]byte("DIMENSION '" +
56 opts.ID + quotes +
57 opts.Name + quotes +
58 opts.Algorithm + quotes +
59 strconv.Itoa(opts.Multiplier) + quotes +
60 strconv.Itoa(opts.Divisor) + quotes +
61 opts.Options + "'\n"))
62 }
63
64 // CLABEL adds or updates a label to the most recently created chart.
65 func (a *API) CLABEL(key, value string, source int) {
66 _, _ = a.Write([]byte("CLABEL '" +
67 key + quotes +
68 value + quotes +
69 strconv.Itoa(source) + "'\n"))
70 }
71
72 // CLABELCOMMIT adds labels to the chart. Should be called after one or more CLABEL.
73 func (a *API) CLABELCOMMIT() {
74 _, _ = a.Write(clabelCommit)
75 }
76
77 // BEGIN initializes data collection for a chart.
78 func (a *API) BEGIN(typeID string, id string, msSince int) {
79 if msSince > 0 {
80 _, _ = a.Write([]byte("BEGIN " + "'" + typeID + "." + id + "' " + strconv.Itoa(msSince) + "\n"))
81 } else {
82 _, _ = a.Write([]byte("BEGIN " + "'" + typeID + "." + id + "'\n"))
83 }
84 }
85
86 // SET sets the value of a dimension for the initialized chart.
87 func (a *API) SET(id string, value int64) {
88 _, _ = a.Write([]byte("SET '" + id + "' = " + strconv.FormatInt(value, 10) + "\n"))
89 }
90
91 // SETFLOAT sets the value of a dimension for the initialized chart.
92 func (a *API) SETFLOAT(id string, value float64) {
93 v := strconv.FormatFloat(value, 'f', -1, 64)
94 _, _ = a.Write([]byte("SET '" + id + "' = " + v + "\n"))
95 }
96
97 // SETEMPTY sets an empty value for a dimension in the initialized chart.
98 func (a *API) SETEMPTY(id string) {
99 _, _ = a.Write([]byte("SET '" + id + "' = \n"))
100 }
101
102 // VARIABLE sets the value of a CHART scope variable for the initialized chart.
103 func (a *API) VARIABLE(ID string, value float64) {
104 v := strconv.FormatFloat(value, 'f', -1, 64)
105 _, _ = a.Write([]byte("VARIABLE CHART '" + ID + "' = " + v + "\n"))
106 }
107
108 // END completes data collection for the initialized chart.
109 // Should be called after all SET operations are complete.
110 func (a *API) END() {
111 _, _ = a.Write(end)
112 }
113
114 // DISABLE disables this plugin.
115 // This will prevent Netdata from restarting the plugin.
116 func (a *API) DISABLE() {
117 _, _ = a.Write([]byte("DISABLE\n"))
118 }
119
120 // EMPTYLINE writes an empty line to the output.
121 func (a *API) EMPTYLINE() error {
122 _, err := a.Write(newLine)
123 return err
124 }
125
126 // HOSTINFO defines a host with its labels.
127 func (a *API) HOSTINFO(info HostInfo) {
128 var buf bytes.Buffer
129
130 _, _ = fmt.Fprintf(&buf, "HOST_DEFINE '%s' '%s'\n", info.GUID, info.Hostname)
131 keys := make([]string, 0, len(info.Labels))
132 for k := range info.Labels {
133 keys = append(keys, k)
134 }
135 sort.Strings(keys)
136 for _, k := range keys {
137 v := info.Labels[k]
138 _, _ = fmt.Fprintf(&buf, "HOST_LABEL '%s' '%s'\n", k, v)
139 }
140 buf.WriteString("HOST_DEFINE_END\n\n")
141
142 _, _ = buf.WriteTo(a)
143 }
144
145 // HOST switches the current context to a specific host.
146 func (a *API) HOST(guid string) {
147 _, _ = a.Write([]byte("HOST " + "'" + guid + "'\n\n"))
148 }
149
150 // FUNCRESULT writes a function result to Netdata.
151 func (a *API) FUNCRESULT(result FunctionResult) {
152 var buf bytes.Buffer
153
154 buf.WriteString("FUNCTION_RESULT_BEGIN " +
155 result.UID + " " +
156 result.Code + " " +
157 result.ContentType + " " +
158 result.ExpireTimestamp + "\n",
159 )
160
161 if result.Payload != "" {
162 buf.WriteString(result.Payload + "\n")
163 }
164
165 buf.WriteString("FUNCTION_RESULT_END\n\n")
166
167 _, _ = buf.WriteTo(a)
168 }
169
170 // CONFIGCREATE creates a new configuration
171 func (a *API) CONFIGCREATE(opts ConfigOpts) {
172 // https://learn.netdata.cloud/docs/contributing/external-plugins/#config
173
174 _, _ = a.Write([]byte("CONFIG " +
175 opts.ID + " " +
176 "create" + " " +
177 opts.Status + " " +
178 opts.ConfigType + " " +
179 opts.Path + " " +
180 opts.SourceType + " '" +
181 opts.Source + "' '" +
182 opts.SupportedCommands + "' 0x0000 0x0000\n\n",
183 ))
184 }
185
186 // CONFIGDELETE deletes a configuration
187 func (a *API) CONFIGDELETE(id string) {
188 _, _ = a.Write([]byte("CONFIG " + id + " delete\n\n"))
189 }
190
191 // CONFIGSTATUS updates a configuration status
192 func (a *API) CONFIGSTATUS(id, status string) {
193 _, _ = a.Write([]byte("CONFIG " + id + " status " + status + "\n\n"))
194 }
195
196 // FUNCTIONGLOBAL registers a global function with Netdata.
197 // Format: FUNCTION GLOBAL "<name>" <timeout> "<help>" "<tags>" <access> <priority> <version>
198 func (a *API) FUNCTIONGLOBAL(opts FunctionGlobalOpts) {
199 _, _ = a.Write([]byte("FUNCTION GLOBAL \"" +
200 opts.Name + "\" " +
201 strconv.Itoa(opts.Timeout) + " \"" +
202 opts.Help + "\" \"" +
203 opts.Tags + "\" " +
204 opts.Access + " " +
205 strconv.Itoa(opts.Priority) + " " +
206 strconv.Itoa(opts.Version) + "\n\n"))
207 }
208
209 // FUNCTIONREMOVE removes a function from Netdata.
210 // NOTE: This is a no-op placeholder - Netdata core does not yet support function removal.
211 // When Netdata implements this, the protocol format will be added here.
212 func (a *API) FUNCTIONREMOVE(name string) {
213 // TODO: Implement when Netdata core supports function removal
214 // For now, this is intentionally a no-op
215 }