master
md 414 lines 13.9 KB
Rendered Raw
1 <!--startmeta
2 custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/pandas/README.md"
3 meta_yaml: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/pandas/metadata.yaml"
4 sidebar_label: "Pandas"
5 learn_status: "Published"
6 learn_rel_path: "Collecting Metrics/Collectors/Databases"
7 keywords: ['pandas', 'python']
8 message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
9 endmeta-->
10
11 # Pandas
12
13
14 <img src="https://netdata.cloud/img/pandas.png" width="150"/>
15
16
17 Plugin: python.d.plugin
18 Module: pandas
19
20 <img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
21
22 ## Overview
23
24 [Pandas](https://pandas.pydata.org/) is a de-facto standard in reading and processing most types of structured data in Python.
25 If you have metrics appearing in a CSV, JSON, XML, HTML, or [other supported format](https://pandas.pydata.org/docs/user_guide/io.html),
26 either locally or via some HTTP endpoint, you can easily ingest and present those metrics in Netdata, by leveraging the Pandas collector.
27
28 This collector can be used to collect pretty much anything that can be read by Pandas, and then processed by Pandas.
29
30
31 The collector uses [pandas](https://pandas.pydata.org/) to pull data and do pandas-based preprocessing, before feeding to Netdata.
32
33
34 This collector is supported on all platforms.
35
36 This collector supports collecting metrics from multiple instances of this integration, including remote instances.
37
38
39 ### Default Behavior
40
41 #### Auto-Detection
42
43 This integration doesn't support auto-detection.
44
45 #### Limits
46
47 The default configuration for this integration does not impose any limits on data collection.
48
49 #### Performance Impact
50
51 The default configuration for this integration is not expected to impose a significant performance impact on the system.
52
53 ## Setup
54
55
56 ### Prerequisites
57
58 #### Python Requirements
59
60 This collector depends on some Python (Python 3 only) packages that can usually be installed via `pip` or `pip3`.
61
62 ```bash
63 sudo pip install pandas requests
64 ```
65
66 Note: If you would like to use [`pandas.read_sql`](https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html) to query a database, you will need to install the below packages as well.
67
68 ```bash
69 sudo pip install 'sqlalchemy<2.0' psycopg2-binary
70 ```
71
72
73
74 ### Configuration
75
76 #### Options
77
78 There are 2 sections:
79
80 * Global variables
81 * One or more JOBS that can define multiple different instances to monitor.
82
83 The following options can be defined globally: priority, penalty, autodetection_retry, update_every, but can also be defined per JOB to override the global values.
84
85 Additionally, the following collapsed table contains all the options that can be configured inside a JOB definition.
86
87 Every configuration JOB starts with a `job_name` value which will appear in the dashboard, unless a `name` parameter is specified.
88
89
90 <details open><summary>Config options</summary>
91
92
93
94 | Option | Description | Default | Required |
95 |:-----|:------------|:--------|:---------:|
96 | chart_configs | an array of chart configuration dictionaries | [] | yes |
97 | chart_configs.name | name of the chart to be displayed in the dashboard. | None | yes |
98 | chart_configs.title | title of the chart to be displayed in the dashboard. | None | yes |
99 | chart_configs.family | [family](https://github.com/netdata/netdata/blob/master/docs/dashboards-and-charts/netdata-charts.md#families) of the chart to be displayed in the dashboard. | None | yes |
100 | chart_configs.context | [context](https://github.com/netdata/netdata/blob/master/docs/dashboards-and-charts/netdata-charts.md#contexts) of the chart to be displayed in the dashboard. | None | yes |
101 | chart_configs.type | the type of the chart to be displayed in the dashboard. | None | yes |
102 | chart_configs.units | the units of the chart to be displayed in the dashboard. | None | yes |
103 | chart_configs.df_steps | a series of pandas operations (one per line) that each returns a dataframe. | None | yes |
104 | update_every | Sets the default data collection frequency. | 5 | no |
105 | priority | Controls the order of charts at the netdata dashboard. | 60000 | no |
106 | autodetection_retry | Sets the job re-check interval in seconds. | 0 | no |
107 | penalty | Indicates whether to apply penalty to update_every in case of failures. | yes | no |
108 | name | Job name. This value will overwrite the `job_name` value. JOBS with the same name are mutually exclusive. Only one of them will be allowed running at any time. This allows autodetection to try several alternatives and pick the one that works. | | no |
109
110
111 </details>
112
113
114
115 #### via File
116
117 The configuration file name for this integration is `python.d/pandas.conf`.
118
119 The file format is YAML. Generally, the structure is:
120
121 ```yaml
122 update_every: 1
123 autodetection_retry: 0
124
125 job_name:
126 job_option1: some_value
127 job_option2: some_other_vlaue
128 ```
129 You can edit the configuration file using the [`edit-config`](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#edit-configuration-files) script from the
130 Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#locate-your-config-directory).
131
132 ```bash
133 cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
134 sudo ./edit-config python.d/pandas.conf
135 ```
136
137 ##### Examples
138
139 ###### Temperature API Example
140
141 example pulling some hourly temperature data, a chart for today forecast (mean,min,max) and another chart for current.
142
143 <details open><summary>Config</summary>
144
145 ```yaml
146 temperature:
147 name: "temperature"
148 update_every: 5
149 chart_configs:
150 - name: "temperature_forecast_by_city"
151 title: "Temperature By City - Today Forecast"
152 family: "temperature.today"
153 context: "pandas.temperature"
154 type: "line"
155 units: "Celsius"
156 df_steps: >
157 pd.DataFrame.from_dict(
158 {city: requests.get(f'https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lng}&hourly=temperature_2m').json()['hourly']['temperature_2m']
159 for (city,lat,lng)
160 in [
161 ('dublin', 53.3441, -6.2675),
162 ('athens', 37.9792, 23.7166),
163 ('london', 51.5002, -0.1262),
164 ('berlin', 52.5235, 13.4115),
165 ('paris', 48.8567, 2.3510),
166 ('madrid', 40.4167, -3.7033),
167 ('new_york', 40.71, -74.01),
168 ('los_angeles', 34.05, -118.24),
169 ]
170 }
171 );
172 df.describe(); # get aggregate stats for each city;
173 df.transpose()[['mean', 'max', 'min']].reset_index(); # just take mean, min, max;
174 df.rename(columns={'index':'city'}); # some column renaming;
175 df.pivot(columns='city').mean().to_frame().reset_index(); # force to be one row per city;
176 df.rename(columns={0:'degrees'}); # some column renaming;
177 pd.concat([df, df['city']+'_'+df['level_0']], axis=1); # add new column combining city and summary measurement label;
178 df.rename(columns={0:'measurement'}); # some column renaming;
179 df[['measurement', 'degrees']].set_index('measurement'); # just take two columns we want;
180 df.sort_index(); # sort by city name;
181 df.transpose(); # transpose so its just one wide row;
182 - name: "temperature_current_by_city"
183 title: "Temperature By City - Current"
184 family: "temperature.current"
185 context: "pandas.temperature"
186 type: "line"
187 units: "Celsius"
188 df_steps: >
189 pd.DataFrame.from_dict(
190 {city: requests.get(f'https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lng}&current_weather=true').json()['current_weather']
191 for (city,lat,lng)
192 in [
193 ('dublin', 53.3441, -6.2675),
194 ('athens', 37.9792, 23.7166),
195 ('london', 51.5002, -0.1262),
196 ('berlin', 52.5235, 13.4115),
197 ('paris', 48.8567, 2.3510),
198 ('madrid', 40.4167, -3.7033),
199 ('new_york', 40.71, -74.01),
200 ('los_angeles', 34.05, -118.24),
201 ]
202 }
203 );
204 df.transpose();
205 df[['temperature']];
206 df.transpose();
207
208 ```
209 </details>
210
211 ###### API CSV Example
212
213 example showing a read_csv from a url and some light pandas data wrangling.
214
215 <details open><summary>Config</summary>
216
217 ```yaml
218 example_csv:
219 name: "example_csv"
220 update_every: 2
221 chart_configs:
222 - name: "london_system_cpu"
223 title: "London System CPU - Ratios"
224 family: "london_system_cpu"
225 context: "pandas"
226 type: "line"
227 units: "n"
228 df_steps: >
229 pd.read_csv('https://london.my-netdata.io/api/v1/data?chart=system.cpu&format=csv&after=-60', storage_options={'User-Agent': 'netdata'});
230 df.drop('time', axis=1);
231 df.mean().to_frame().transpose();
232 df.apply(lambda row: (row.user / row.system), axis = 1).to_frame();
233 df.rename(columns={0:'average_user_system_ratio'});
234 df*100;
235
236 ```
237 </details>
238
239 ###### API JSON Example
240
241 example showing a read_json from a url and some light pandas data wrangling.
242
243 <details open><summary>Config</summary>
244
245 ```yaml
246 example_json:
247 name: "example_json"
248 update_every: 2
249 chart_configs:
250 - name: "london_system_net"
251 title: "London System Net - Total Bandwidth"
252 family: "london_system_net"
253 context: "pandas"
254 type: "area"
255 units: "kilobits/s"
256 df_steps: >
257 pd.DataFrame(requests.get('https://london.my-netdata.io/api/v1/data?chart=system.net&format=json&after=-1').json()['data'], columns=requests.get('https://london.my-netdata.io/api/v1/data?chart=system.net&format=json&after=-1').json()['labels']);
258 df.drop('time', axis=1);
259 abs(df);
260 df.sum(axis=1).to_frame();
261 df.rename(columns={0:'total_bandwidth'});
262
263 ```
264 </details>
265
266 ###### XML Example
267
268 example showing a read_xml from a url and some light pandas data wrangling.
269
270 <details open><summary>Config</summary>
271
272 ```yaml
273 example_xml:
274 name: "example_xml"
275 update_every: 2
276 line_sep: "|"
277 chart_configs:
278 - name: "temperature_forcast"
279 title: "Temperature Forecast"
280 family: "temp"
281 context: "pandas.temp"
282 type: "line"
283 units: "celsius"
284 df_steps: >
285 pd.read_xml('http://metwdb-openaccess.ichec.ie/metno-wdb2ts/locationforecast?lat=54.7210798611;long=-8.7237392806', xpath='./product/time[1]/location/temperature', parser='etree')|
286 df.rename(columns={'value': 'dublin'})|
287 df[['dublin']]|
288
289 ```
290 </details>
291
292 ###### SQL Example
293
294 example showing a read_sql from a postgres database using sqlalchemy.
295
296 <details open><summary>Config</summary>
297
298 ```yaml
299 sql:
300 name: "sql"
301 update_every: 5
302 chart_configs:
303 - name: "sql"
304 title: "SQL Example"
305 family: "sql.example"
306 context: "example"
307 type: "line"
308 units: "percent"
309 df_steps: >
310 pd.read_sql_query(
311 sql='\
312 select \
313 random()*100 as metric_1, \
314 random()*100 as metric_2 \
315 ',
316 con=create_engine('postgresql://localhost/postgres?user=netdata&password=netdata')
317 );
318
319 ```
320 </details>
321
322
323
324 ## Alerts
325
326 There are no alerts configured by default for this integration.
327
328
329 ## Metrics
330
331 Metrics grouped by *scope*.
332
333 The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
334
335 This collector is expecting one row in the final pandas DataFrame. It is that first row that will be taken
336 as the most recent values for each dimension on each chart using (`df.to_dict(orient='records')[0]`).
337 See [pd.to_dict()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_dict.html)."
338
339
340 ### Per Pandas instance
341
342 These metrics refer to the entire monitored application.
343
344
345 This scope has no labels.
346
347 Metrics:
348
349 | Metric | Dimensions | Unit |
350 |:------|:----------|:----|
351
352
353
354 ## Troubleshooting
355
356 ### Debug Mode
357
358
359 To troubleshoot issues with the `pandas` collector, run the `python.d.plugin` with the debug option enabled. The output
360 should give you clues as to why the collector isn't working.
361
362 - Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on
363 your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`.
364
365 ```bash
366 cd /usr/libexec/netdata/plugins.d/
367 ```
368
369 - Switch to the `netdata` user.
370
371 ```bash
372 sudo -u netdata -s
373 ```
374
375 - Run the `python.d.plugin` to debug the collector:
376
377 ```bash
378 ./python.d.plugin pandas debug trace
379 ```
380
381 ### Getting Logs
382
383 If you're encountering problems with the `pandas` collector, follow these steps to retrieve logs and identify potential issues:
384
385 - **Run the command** specific to your system (systemd, non-systemd, or Docker container).
386 - **Examine the output** for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem.
387
388 #### System with systemd
389
390 Use the following command to view logs generated since the last Netdata service restart:
391
392 ```bash
393 journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep pandas
394 ```
395
396 #### System without systemd
397
398 Locate the collector log file, typically at `/var/log/netdata/collector.log`, and use `grep` to filter for collector's name:
399
400 ```bash
401 grep pandas /var/log/netdata/collector.log
402 ```
403
404 **Note**: This method shows logs from all restarts. Focus on the **latest entries** for troubleshooting current issues.
405
406 #### Docker Container
407
408 If your Netdata runs in a Docker container named "netdata" (replace if different), use this command:
409
410 ```bash
411 docker logs netdata 2>&1 | grep pandas
412 ```
413
414