Skip to content

Commit 1e491f4

Browse files
eskyuumurrant
andauthored
Convert rrd_options to an array for use when generating graphs (librenms#18485)
* Move rrd_options to be an array and use PHP RRD package if it's installed * Style fixes * Convert all array += to array_push * Move php-rrd code into LibreNMS/Data/Store/Rrd.php * Split generic prints into separate options * Split double GPRINT lines into separate options * Style fixes * PHPStan fixes * PHPStan fixes * Filter out quotes from all arguments * Remove test for rrd_graph function * Reactor fixes * Re-add init on Rrd.pm * Do not remove quotes from the options (will likely cause formatting errors) * Fixed formatting for includes/html/graphs/generic_multi_seperated.inc.php * Fix formatting in includes/html/graphs/mempool/usage.inc.php * Fix formatting in includes/html/graphs/generic_stats.inc.php * Another graph formatting fix * More formatting fixes for graphs * More graph formatting fixes * More formatting fixes * Change where graph_params->toRrdOptions() is added to the options to ensure changes made by graph includes are reflected in the graph * More graph formatting fixes * iStyleCI fixes * Reduce description width for some graphs on narrow images * Re-align headers for narrower graphs * More graph formatting fixes * StyleCI fixes * More graph formatting fixes * StyleCI fixes * Fix global poller perf formatting * StyleCI fixes * Revert back to using the rrdtool pipe, and added a function to build a rrd command from an array * Style and PHPSTAN fixes * Remove extra quotes from includes/html/graphs/generic_multi_line.inc.php * StyleCI changes * PHPStan fixes * Update the phpstan baseline after fixing an error * Fix quoting in includes/html/graphs/XXX_device_memory_windows.inc.php * StyleCI changes * Remove single quotes from all options * StyleCI * StyleCI * Fix remaining graph files with double or single quotes as arguments * StyleCI * Revert back to original newline logic for a few files * We don't need to use escapeshellarg() any more for the graph title * Fix the custom_graph from the bill module to be an array * StyleCI * Fixed newline issue in includes/html/graphs/generic_multi_bits_separated.inc.php * Fixed another issue in includes/html/graphs/generic_multi_bits_separated.inc.php * Do not duplicate buildCommand code Convert everything to send options as an array * Style fixes * Bug in imgformat parsing * Fix test data * Test fix * Fix ds file migration (and add test) * Fix RrdtoolTest --------- Co-authored-by: Tony Murray <[email protected]>
1 parent c6b8e4c commit 1e491f4

File tree

195 files changed

+3661
-3497
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

195 files changed

+3661
-3497
lines changed

LibreNMS/Data/Graphing/GraphParameters.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public function toRrdOptions(): array
192192

193193
if ($this->visible('title')) {
194194
// remove single quotes, because we can't drop out of the string if this is sent to rrdtool stdin
195-
$options[] = '--title=' . escapeshellarg(str_replace("'", '', $this->getTitle()));
195+
$options[] = '--title=' . str_replace("'", '', $this->getTitle());
196196
}
197197

198198
return $options;

LibreNMS/Data/Store/Rrd.php

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ class Rrd extends BaseDatastore
5656
private $version;
5757
/** @var string */
5858
private $rrdcached;
59-
/** @var string */
60-
private $rra;
59+
60+
private array $rra;
6161
/** @var int */
6262
private $step;
6363
/** @var string */
@@ -84,13 +84,13 @@ protected function loadConfig(): void
8484
$this->rrdcached = LibrenmsConfig::get('rrdcached', false);
8585
$this->rrd_dir = LibrenmsConfig::get('rrd_dir', LibrenmsConfig::get('install_dir') . '/rrd');
8686
$this->step = LibrenmsConfig::get('rrd.step', 300);
87-
$this->rra = LibrenmsConfig::get(
87+
$this->rra = preg_split('/s+/', trim(LibrenmsConfig::get(
8888
'rrd_rra',
8989
'RRA:AVERAGE:0.5:1:2016 RRA:AVERAGE:0.5:6:1440 RRA:AVERAGE:0.5:24:1440 RRA:AVERAGE:0.5:288:1440 ' .
9090
' RRA:MIN:0.5:1:2016 RRA:MIN:0.5:6:1440 RRA:MIN:0.5:24:1440 RRA:MIN:0.5:288:1440 ' .
9191
' RRA:MAX:0.5:1:2016 RRA:MAX:0.5:6:1440 RRA:MAX:0.5:24:1440 RRA:MAX:0.5:288:1440 ' .
9292
' RRA:LAST:0.5:1:2016 '
93-
);
93+
)));
9494
$this->version = LibrenmsConfig::get('rrdtool_version', '1.4');
9595
$this->rrdtool_executable = LibrenmsConfig::get('rrdtool', 'rrdtool');
9696
}
@@ -189,8 +189,8 @@ public function write(string $measurement, array $fields, array $tags = [], arra
189189
}, ARRAY_FILTER_USE_KEY);
190190

191191
if (! $this->checkRrdExists($rrd)) {
192-
$newdef = "--step $step $rrd_def $this->rra";
193-
$this->command('create', $rrd, $newdef);
192+
$options = ['--step', $step, ...$rrd_def->getArguments(), ...$this->rra];
193+
$this->command('create', $rrd, $options);
194194
}
195195
}
196196

@@ -199,7 +199,7 @@ public function write(string $measurement, array $fields, array $tags = [], arra
199199

200200
public function lastUpdate(string $filename): ?TimeSeriesPoint
201201
{
202-
$output = $this->command('lastupdate', $filename, '')[0];
202+
$output = $this->command('lastupdate', $filename)[0];
203203

204204
if (preg_match('/((?: \w+)+)\n\n(\d+):((?: [\d.-]+)+)\nOK/', (string) $output, $matches)) {
205205
$data = array_combine(
@@ -242,7 +242,7 @@ public function update($filename, $data): array
242242

243243
$data = implode(':', $values);
244244

245-
return $this->command('update', $filename, $data);
245+
return $this->command('update', $filename, [$data]);
246246
}
247247

248248
throw new RrdException('Bad options passed to rrdtool_update');
@@ -285,7 +285,10 @@ public function tune($type, $filename, $max): bool
285285
];
286286
}
287287
if (count($fields) > 0) {
288-
$options = '--maximum ' . implode(":$max --maximum ", $fields) . ":$max";
288+
$options = [];
289+
foreach ($fields as $field) {
290+
array_push($options, '--maximum', $field . ':' . $max);
291+
}
289292
$this->command('tune', $filename, $options);
290293
}
291294

@@ -388,12 +391,12 @@ public function dirFromHost($host): string
388391
*
389392
* @param string $command create, update, updatev, graph, graphv, dump, restore, fetch, tune, first, last, lastupdate, info, resize, xport, flushcached
390393
* @param string $filename The full patth to the rrd file
391-
* @param string $options rrdtool command options
394+
* @param array $options rrdtool command options
392395
* @return array the output of stdout and stderr in an array
393396
*
394397
* @throws \Exception thrown when the rrdtool process(s) cannot be started
395398
*/
396-
private function command($command, $filename, $options): array
399+
private function command(string $command, string $filename, array $options = []): array
397400
{
398401
$stat = Measurement::start($this->coalesceStatisticType($command));
399402
$output = null;
@@ -406,7 +409,7 @@ private function command($command, $filename, $options): array
406409
return [null, null];
407410
}
408411

409-
Log::debug("RRD[%g$cmd%n]", ['color' => true]);
412+
Log::debug('RRD[%g' . implode(' ', $cmd) . '%n]', ['color' => true]);
410413

411414
// do not write rrd files, but allow read-only commands
412415
$ro_commands = ['graph', 'graphv', 'dump', 'fetch', 'first', 'last', 'lastupdate', 'info', 'xport'];
@@ -421,10 +424,10 @@ private function command($command, $filename, $options): array
421424
// send the command!
422425
if (in_array($command, ['last', 'list', 'lastupdate']) && $this->init(false)) {
423426
// send this to our synchronous process so output is guaranteed
424-
$output = $this->sync_process->sendCommand($cmd);
427+
$output = $this->sync_process->sendCommand(implode(' ', $cmd));
425428
} elseif ($this->init()) {
426429
// don't care about the return of other commands, so send them to the faster async process
427-
$output = $this->async_process->sendCommand($cmd);
430+
$output = $this->async_process->sendCommand(implode(' ', $cmd));
428431
} else {
429432
Log::error('rrdtool could not start');
430433
}
@@ -441,20 +444,18 @@ private function command($command, $filename, $options): array
441444
}
442445

443446
/**
444-
* Build a command for rrdtool
447+
* Build a command array for rrdtool
445448
* Shortens the filename as needed
446-
* Determines if --daemon and -O should be used
447-
*
448-
* @internal
449+
* Determines if --daemon should be used
449450
*
450451
* @param string $command The base rrdtool command. Usually create, update, last.
451452
* @param string $filename The full path to the rrd file
452-
* @param string $options Options for the command possibly including the rrd definition
453-
* @return string returns a full command ready to be piped to rrdtool
453+
* @param array $options Options for the command possibly including the rrd definition
454+
* @return array returns a full command array ready to be used by rrdtool
454455
*
455456
* @throws FileExistsException if rrdtool <1.4.3 and the rrd file exists locally
456457
*/
457-
public function buildCommand($command, $filename, $options): string
458+
public function buildCommand(string $command, string $filename, array $options = []): array
458459
{
459460
if ($command == 'create') {
460461
// <1.4.3 doesn't support -O, so make sure the file doesn't exist
@@ -463,23 +464,22 @@ public function buildCommand($command, $filename, $options): string
463464
throw new FileExistsException();
464465
}
465466
} else {
466-
$options .= ' -O';
467+
$options[] = '-O';
467468
}
468469
}
469470

470-
// no remote for create < 1.5.5 and tune < 1.5
471471
if ($this->rrdcached &&
472472
! ($command == 'create' && version_compare($this->version, '1.5.5', '<')) &&
473-
! ($command == 'tune' && $this->rrdcached && version_compare($this->version, '1.5', '<'))
473+
! ($command == 'tune' && version_compare($this->version, '1.5', '<'))
474474
) {
475475
// only relative paths if using rrdcached
476476
$filename = str_replace([$this->rrd_dir . '/', $this->rrd_dir], '', $filename);
477477
$options = str_replace([$this->rrd_dir . '/', $this->rrd_dir], '', $options);
478478

479-
return "$command $filename $options --daemon " . $this->rrdcached;
479+
return [$command, $filename, '--daemon', $this->rrdcached, ...$options];
480480
}
481481

482-
return "$command $filename $options";
482+
return [$command, $filename, ...$options];
483483
}
484484

485485
/**
@@ -493,7 +493,7 @@ public function getRrdFiles($device)
493493
{
494494
if ($this->rrdcached) {
495495
$filename = sprintf('/%s', self::safeName($device['hostname']));
496-
$rrd_files = $this->command('list', $filename, '');
496+
$rrd_files = $this->command('list', $filename);
497497
// Command output is an array, create new array with each filename as a item in array.
498498
$rrd_files_array = explode("\n", trim((string) $rrd_files[0]));
499499
// Remove status line from response
@@ -556,7 +556,7 @@ public function getRrdApplicationArrays($device, $app_id, $app_name, $category =
556556
public function checkRrdExists($filename): bool
557557
{
558558
if ($this->rrdcached && version_compare($this->version, '1.5', '>=')) {
559-
$check_output = implode('', $this->command('last', $filename, ''));
559+
$check_output = implode('', $this->command('last', $filename));
560560
$filename = str_replace([$this->rrd_dir . '/', $this->rrd_dir], '', $filename);
561561

562562
return ! (str_contains($check_output, $filename) && str_contains($check_output, 'No such file or directory'));
@@ -588,21 +588,21 @@ public function purge($hostname, $prefix): void
588588
* Generates a graph file at $graph_file using $options
589589
* Graphs are a single command per run, so this just runs rrdtool
590590
*
591-
* @param string $options
591+
* @param array $options
592592
* @param array|null $env
593593
* @return string
594594
*
595595
* @throws RrdGraphException
596596
*/
597-
public function graph(string $options, ?array $env = null): string
597+
public function graph(array $options, ?array $env = null): string
598598
{
599599
$process = new Process([$this->rrdtool_executable, '-'], $this->rrd_dir, $env);
600600
$process->setTimeout(300);
601601
$process->setIdleTimeout(300);
602602

603603
try {
604604
$command = $this->buildCommand('graph', '-', $options);
605-
$process->setInput($command . "\nquit");
605+
$process->setInput('"' . implode('" "', $command) . "\"\nquit");
606606
$process->run();
607607
} catch (FileExistsException $e) {
608608
throw new RrdGraphException($e->getMessage(), 'File Exists');
@@ -615,7 +615,8 @@ public function graph(string $options, ?array $env = null): string
615615

616616
// if valid image is returned with error, extract image and feedback
617617
// rrdtool defaults to png if imgformat not specified
618-
$graph_type = preg_match('/--imgformat=([^\s]+)/', $options, $matches) ? strtolower($matches[1]) : 'png';
618+
$imgformat_option = array_find($options, fn ($o) => str_starts_with((string) $o, '--imgformat='));
619+
$graph_type = $imgformat_option ? strtolower(substr((string) $imgformat_option, 12)) : 'png';
619620
$imageFormat = ImageFormat::forGraph($graph_type);
620621

621622
$search = $imageFormat->getImageEnd();

LibreNMS/RRD/RrdDefinition.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,23 @@ public function addDataset($name, $type, $min = null, $max = null, $heartbeat =
8585
*/
8686
public function __toString(): string
8787
{
88-
$def = array_reduce($this->dataSets, function ($carry, $ds) {
88+
return implode(' ', $this->getArguments());
89+
}
90+
91+
public function getArguments(): array
92+
{
93+
$def = [];
94+
95+
foreach ($this->dataSets as $ds) {
8996
$name = $ds['name'] . $this->createSource($ds['source_ds'], $ds['source_file']);
97+
$def[] = "DS:$name:{$ds['type']}:{$ds['hb']}:{$ds['min']}:{$ds['max']}";
98+
}
9099

91-
return $carry . "DS:$name:{$ds['type']}:{$ds['hb']}:{$ds['min']}:{$ds['max']} ";
92-
}, '');
93-
$sources = implode(' ', array_map(fn ($s) => "--source $s ", $this->sources));
100+
foreach ($this->sources as $source) {
101+
array_unshift($def, '--source', $source);
102+
}
94103

95-
return $sources . $def;
104+
return $def;
96105
}
97106

98107
/**

includes/html/graphs/XXX_device_memory_windows.inc.php

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,60 @@
66

77
$rrd_filename = Rrd::name($device['hostname'], 'mem');
88

9-
$rrd_options .= ' -b 1024';
9+
$rrd_options[] = '-b';
10+
$rrd_options[] = '1024';
1011

11-
$rrd_options .= " DEF:atotalswap=$rrd_filename:totalswap:AVERAGE";
12-
$rrd_options .= " DEF:aavailswap=$rrd_filename:availswap:AVERAGE";
13-
$rrd_options .= " DEF:atotalreal=$rrd_filename:totalreal:AVERAGE";
14-
$rrd_options .= " DEF:aavailreal=$rrd_filename:availreal:AVERAGE";
15-
$rrd_options .= " DEF:atotalfree=$rrd_filename:totalfree:AVERAGE";
16-
$rrd_options .= " DEF:ashared=$rrd_filename:shared:AVERAGE";
17-
$rrd_options .= " DEF:abuffered=$rrd_filename:buffered:AVERAGE";
18-
$rrd_options .= " DEF:acached=$rrd_filename:cached:AVERAGE";
19-
$rrd_options .= ' CDEF:totalswap=atotalswap,1024,*';
20-
$rrd_options .= ' CDEF:availswap=aavailswap,1024,*';
21-
$rrd_options .= ' CDEF:totalreal=atotalreal,1024,*';
22-
$rrd_options .= ' CDEF:availreal=aavailreal,1024,*';
23-
$rrd_options .= ' CDEF:totalfree=atotalfree,1024,*';
24-
$rrd_options .= ' CDEF:shared=ashared,1024,*';
25-
$rrd_options .= ' CDEF:buffered=abuffered,1024,*';
26-
$rrd_options .= ' CDEF:cached=acached,1024,*';
27-
$rrd_options .= ' CDEF:usedreal=totalreal,availreal,-';
28-
$rrd_options .= ' CDEF:usedswap=totalswap,availswap,-';
29-
$rrd_options .= ' CDEF:cusedswap=usedswap,-1,*';
30-
$rrd_options .= ' CDEF:cdeftot=availreal,shared,buffered,usedreal,cached,usedswap,+,+,+,+,+';
31-
$rrd_options .= " COMMENT:'Bytes Current Average Maximum\\n'";
32-
$rrd_options .= ' LINE1:usedreal#d0b080:';
33-
$rrd_options .= ' AREA:usedreal#f0e0a0:used';
34-
$rrd_options .= ' GPRINT:usedreal:LAST:\ \ \ %7.2lf%sB';
35-
$rrd_options .= ' GPRINT:usedreal:AVERAGE:%7.2lf%sB';
36-
$rrd_options .= ' GPRINT:usedreal:MAX:%7.2lf%sB\\\\n';
37-
$rrd_options .= ' STACK:availreal#e5e5e5:free';
38-
$rrd_options .= ' GPRINT:availreal:LAST:\ \ \ %7.2lf%sB';
39-
$rrd_options .= ' GPRINT:availreal:AVERAGE:%7.2lf%sB';
40-
$rrd_options .= ' GPRINT:availreal:MAX:%7.2lf%sB\\\\n';
41-
$rrd_options .= ' LINE1:usedreal#d0b080:';
42-
$rrd_options .= ' AREA:shared#afeced:';
43-
$rrd_options .= ' AREA:buffered#cc0000::STACK';
44-
$rrd_options .= ' AREA:cached#ffaa66::STACK';
45-
$rrd_options .= ' LINE1.25:shared#008fea:shared';
46-
$rrd_options .= ' GPRINT:shared:LAST:\ %7.2lf%sB';
47-
$rrd_options .= ' GPRINT:shared:AVERAGE:%7.2lf%sB';
48-
$rrd_options .= ' GPRINT:shared:MAX:%7.2lf%sB\\\\n';
49-
$rrd_options .= ' LINE1.25:buffered#ff1a00:buffers:STACK';
50-
$rrd_options .= ' GPRINT:buffered:LAST:%7.2lf%sB';
51-
$rrd_options .= ' GPRINT:buffered:AVERAGE:%7.2lf%sB';
52-
$rrd_options .= ' GPRINT:buffered:MAX:%7.2lf%sB\\\\n';
53-
$rrd_options .= ' LINE1.25:cached#ea8f00:cached:STACK';
54-
$rrd_options .= ' GPRINT:cached:LAST:\ %7.2lf%sB';
55-
$rrd_options .= ' GPRINT:cached:AVERAGE:%7.2lf%sB';
56-
$rrd_options .= ' GPRINT:cached:MAX:%7.2lf%sB\\\\n';
57-
$rrd_options .= ' LINE1:totalreal#050505:';
58-
$rrd_options .= ' AREA:cusedswap#C3D9FF:swap';
59-
$rrd_options .= ' LINE1.25:cusedswap#356AA0:';
60-
$rrd_options .= ' GPRINT:usedswap:LAST:\ \ \ %7.2lf%sB';
61-
$rrd_options .= ' GPRINT:usedswap:AVERAGE:%7.2lf%sB';
62-
$rrd_options .= ' GPRINT:usedswap:MAX:%7.2lf%sB\\\\n';
63-
$rrd_options .= ' LINE1:totalreal#050505:total';
64-
$rrd_options .= ' GPRINT:totalreal:AVERAGE:\ \ %7.2lf%sB';
12+
$rrd_options[] = "DEF:atotalswap=$rrd_filename:totalswap:AVERAGE";
13+
$rrd_options[] = "DEF:aavailswap=$rrd_filename:availswap:AVERAGE";
14+
$rrd_options[] = "DEF:atotalreal=$rrd_filename:totalreal:AVERAGE";
15+
$rrd_options[] = "DEF:aavailreal=$rrd_filename:availreal:AVERAGE";
16+
$rrd_options[] = "DEF:atotalfree=$rrd_filename:totalfree:AVERAGE";
17+
$rrd_options[] = "DEF:ashared=$rrd_filename:shared:AVERAGE";
18+
$rrd_options[] = "DEF:abuffered=$rrd_filename:buffered:AVERAGE";
19+
$rrd_options[] = "DEF:acached=$rrd_filename:cached:AVERAGE";
20+
$rrd_options[] = 'CDEF:totalswap=atotalswap,1024,*';
21+
$rrd_options[] = 'CDEF:availswap=aavailswap,1024,*';
22+
$rrd_options[] = 'CDEF:totalreal=atotalreal,1024,*';
23+
$rrd_options[] = 'CDEF:availreal=aavailreal,1024,*';
24+
$rrd_options[] = 'CDEF:totalfree=atotalfree,1024,*';
25+
$rrd_options[] = 'CDEF:shared=ashared,1024,*';
26+
$rrd_options[] = 'CDEF:buffered=abuffered,1024,*';
27+
$rrd_options[] = 'CDEF:cached=acached,1024,*';
28+
$rrd_options[] = 'CDEF:usedreal=totalreal,availreal,-';
29+
$rrd_options[] = 'CDEF:usedswap=totalswap,availswap,-';
30+
$rrd_options[] = 'CDEF:cusedswap=usedswap,-1,*';
31+
$rrd_options[] = 'CDEF:cdeftot=availreal,shared,buffered,usedreal,cached,usedswap,+,+,+,+,+';
32+
$rrd_options[] = 'COMMENT:Bytes Current Average Maximum\\n';
33+
$rrd_options[] = 'LINE1:usedreal#d0b080:';
34+
$rrd_options[] = 'AREA:usedreal#f0e0a0:used';
35+
$rrd_options[] = 'GPRINT:usedreal:LAST:\ \ \ %7.2lf%sB';
36+
$rrd_options[] = 'GPRINT:usedreal:AVERAGE:%7.2lf%sB';
37+
$rrd_options[] = 'GPRINT:usedreal:MAX:%7.2lf%sB\\\\n';
38+
$rrd_options[] = 'STACK:availreal#e5e5e5:free';
39+
$rrd_options[] = 'GPRINT:availreal:LAST:\ \ \ %7.2lf%sB';
40+
$rrd_options[] = 'GPRINT:availreal:AVERAGE:%7.2lf%sB';
41+
$rrd_options[] = 'GPRINT:availreal:MAX:%7.2lf%sB\\\\n';
42+
$rrd_options[] = 'LINE1:usedreal#d0b080:';
43+
$rrd_options[] = 'AREA:shared#afeced:';
44+
$rrd_options[] = 'AREA:buffered#cc0000::STACK';
45+
$rrd_options[] = 'AREA:cached#ffaa66::STACK';
46+
$rrd_options[] = 'LINE1.25:shared#008fea:shared';
47+
$rrd_options[] = 'GPRINT:shared:LAST:\ %7.2lf%sB';
48+
$rrd_options[] = 'GPRINT:shared:AVERAGE:%7.2lf%sB';
49+
$rrd_options[] = 'GPRINT:shared:MAX:%7.2lf%sB\\\\n';
50+
$rrd_options[] = 'LINE1.25:buffered#ff1a00:buffers:STACK';
51+
$rrd_options[] = 'GPRINT:buffered:LAST:%7.2lf%sB';
52+
$rrd_options[] = 'GPRINT:buffered:AVERAGE:%7.2lf%sB';
53+
$rrd_options[] = 'GPRINT:buffered:MAX:%7.2lf%sB\\\\n';
54+
$rrd_options[] = 'LINE1.25:cached#ea8f00:cached:STACK';
55+
$rrd_options[] = 'GPRINT:cached:LAST:\ %7.2lf%sB';
56+
$rrd_options[] = 'GPRINT:cached:AVERAGE:%7.2lf%sB';
57+
$rrd_options[] = 'GPRINT:cached:MAX:%7.2lf%sB\\\\n';
58+
$rrd_options[] = 'LINE1:totalreal#050505:';
59+
$rrd_options[] = 'AREA:cusedswap#C3D9FF:swap';
60+
$rrd_options[] = 'LINE1.25:cusedswap#356AA0:';
61+
$rrd_options[] = 'GPRINT:usedswap:LAST:\ \ \ %7.2lf%sB';
62+
$rrd_options[] = 'GPRINT:usedswap:AVERAGE:%7.2lf%sB';
63+
$rrd_options[] = 'GPRINT:usedswap:MAX:%7.2lf%sB\\\\n';
64+
$rrd_options[] = 'LINE1:totalreal#050505:total';
65+
$rrd_options[] = 'GPRINT:totalreal:AVERAGE:\ \ %7.2lf%sB';

0 commit comments

Comments
 (0)