contrib/rrd_filter.px: Added a scale and shift filter.
authorFlorian Forster <octo@noris.net>
Thu, 13 Mar 2008 11:33:50 +0000 (12:33 +0100)
committerFlorian Forster <octo@noris.net>
Thu, 13 Mar 2008 11:33:50 +0000 (12:33 +0100)
contrib/rrd_filter.px

index a212de5..6a82783 100755 (executable)
@@ -48,6 +48,11 @@ our $NewRRAs = [];
 
 our $Step = 0;
 
+our $Scale = 1.0;
+our $Shift = 0.0;
+
+our $Debug = 0;
+
 =head1 OPTIONS
 
 The following options can be passed on the command line:
@@ -100,6 +105,15 @@ Inserts a new RRA in the generated RRD file. This is done B<after> the step has
 been adjusted, take that into account when specifying I<steps> and I<rows>. For
 an explanation of the format please see L<rrdcreate(1)>.
 
+=item B<--scale> I<factor>
+
+Scales the values by the factor I<factor>, i.E<nbsp>e. all values are
+multiplied by I<factor>.
+
+=item B<--shift> I<offset>
+
+Shifts all values by I<offset>, i.E<nbsp>e. I<offset> is added to all values.
+
 =back
 
 =cut
@@ -127,7 +141,9 @@ GetOptions ("infile|i=s" => \$InFile,
                        exit (1);
                }
                push (@$NewRRAs, {cf => $cf, xff => $xff, steps => $steps, rows => $rows});
-       }
+       },
+       'scale=f' => \$Scale,
+       'shift=f' => \$Shift
 ) or exit (1);
 
 if (!$InFile || !$OutFile)
@@ -174,6 +190,7 @@ sub handle_line_dsmap
                $ds_index = [];
                for (my $i = 0; $i < @$InDS; $i++)
                {
+                       print STDOUT "DS map $i: $InDS->[$i] -> $OutDS->[$i]\n" if ($Debug);
                        $ds_index->[$i] = -1;
                }
        }
@@ -203,6 +220,14 @@ sub handle_line_dsmap
 
                        $out_cache->[$current_index] .= $line;
                }
+               elsif ($line =~ m#<last_ds>\s*([^\s>]+)\s*</last_ds>#i)
+               {
+                       $out_cache->[$current_index] .= "\t\t<last_ds> NaN </last_ds>\n";
+               }
+               elsif ($line =~ m#<value>\s*([^\s>]+)\s*</value>#i)
+               {
+                       $out_cache->[$current_index] .= "\t\t<value> NaN </value>\n";
+               }
                elsif ($line =~ m#</ds>#)
                {
                        $out_cache->[$current_index] .= $line;
@@ -247,6 +272,10 @@ sub handle_line_dsmap
                        $current_index++;
                        $out_cache->[$current_index] .= $line;
                }
+               elsif ($line =~ m#<value>\s*([^\s>]+)\s*</value>#i)
+               {
+                       $out_cache->[$current_index] .= "\t\t\t<value> NaN </value>\n";
+               }
                elsif ($line =~ m#</cdp_prep>#)
                {
                        # Print out all the DS definitions we need
@@ -349,6 +378,11 @@ sub handle_line_step
                return;
        }
 
+       if ($Debug && !defined ($step_factor_up))
+       {
+               print STDOUT "New step: $Step\n";
+       }
+
        $step_factor_up ||= 0;
        $step_factor_down ||= 0;
 
@@ -441,6 +475,12 @@ sub handle_line_add_rra
     {
       my $rra = $NewRRAs->[$i];
       my $temp;
+
+      if ($Debug)
+      {
+       print STDOUT "Adding RRA: CF = $rra->{'cf'}, xff = $rra->{'xff'}, steps = $rra->{'steps'}, rows = $rra->{'rows'}, num_ds = $num_ds\n";
+      }
+
       $post->("\t<rra>\n",
       "\t\t<cf> $rra->{'cf'} </cf>\n",
       "\t\t<pdp_per_row> $rra->{'steps'} </pdp_per_row>\n",
@@ -465,16 +505,53 @@ sub handle_line_add_rra
       {
        $post->($temp);
       }
-      $post->("\t\t</database>\n");
+      $post->("\t\t</database>\n", "\t</rra>\n");
     }
+
+    $add_rra_done = 1;
   }
 
   $post->($line);
 }} # handle_line_add_rra
 
 #
+# The _scale/shift_ handler
+#
+sub calculate_scale_shift 
+{
+  my $value = shift;
+  my $tag = shift;
+  my $scale = shift;
+  my $shift = shift;
+
+  if (lc ("$value") eq 'nan')
+  {
+    $value = 'NaN';
+    return ("<$tag> NaN </$tag>");
+  }
+
+  $value = ($scale * (0.0 + $value)) + $shift;
+  return (sprintf ("<%s> %1.10e </%s>", $tag, $value, $tag));
+}
+
+sub handle_line_scale_shift
+{
+  my $line = shift;
+  my $index = shift;
+
+  if (($Scale != 1.0) || ($Shift != 0.0))
+  {
+    $line =~ s#<(min|max|last_ds|value|primary_value|secondary_value|v)>\s*([^\s<]+)\s*</[^>]+>#calculate_scale_shift ($2, $1, $Scale, $Shift)#eg;
+  }
+
+  post_line ($line, $index + 1);
+}
+
+#
 # The _output_ handler
 #
+# This filter is unfinished!
+#
 {
 my $fh;
 sub set_output
@@ -482,6 +559,79 @@ sub set_output
        $fh = shift;
 }
 
+{
+my $previous_values;
+my $previous_differences;
+my $pdp_per_row;
+sub handle_line_peak_detect
+{
+  my $line = shift;
+  my $index = shift;
+
+  if (!$previous_values)
+  {
+    $previous_values = [];
+    $previous_differences = [];
+  }
+
+  if ($line =~ m#</database>#i)
+  {
+    $previous_values = [];
+    $previous_differences = [];
+    print STDERR "==============================================================================\n";
+  }
+  elsif ($line =~ m#<pdp_per_row>\s*([1-9][0-9]*)\s*</pdp_per_row>#)
+  {
+    $pdp_per_row = int ($1);
+    print STDERR "pdp_per_row = $pdp_per_row;\n";
+  }
+  elsif ($line =~ m#<row>#)
+  {
+    my @values = ();
+    while ($line =~ m#<v>\s*([^\s>]+)\s*</v>#ig)
+    {
+      if ($1 eq 'NaN')
+      {
+       push (@values, undef);
+      }
+      else
+      {
+       push (@values, 0.0 + $1);
+      }
+    }
+
+    for (my $i = 0; $i < @values; $i++)
+    {
+      if (!defined ($values[$i]))
+      {
+       $previous_values->[$i] = undef;
+      }
+      elsif (!defined ($previous_values->[$i]))
+      {
+       $previous_values->[$i] = $values[$i];
+      }
+      elsif (!defined ($previous_differences->[$i]))
+      {
+       $previous_differences->[$i] = abs ($previous_values->[$i] - $values[$i]);
+      }
+      else
+      {
+       my $divisor = ($previous_differences->[$i] < 1.0) ? 1.0 : $previous_differences->[$i];
+       my $difference = abs ($previous_values->[$i] - $values[$i]);
+       my $change = $pdp_per_row * $difference / $divisor;
+       if (($divisor > 10.0) &&  ($change > 10e5))
+       {
+         print STDERR "i = $i; average difference = " . $previous_differences->[$i]. "; current difference = " . $difference. "; change = $change;\n";
+       }
+       $previous_values->[$i] = $values[$i];
+       $previous_differences->[$i] = (0.95 * $previous_differences->[$i]) + (0.05 * $difference);
+      }
+    }
+  }
+
+  post_line ($line, $index + 1);
+}} # handle_line_peak_detect
+
 sub handle_line_output
 {
        my $line = shift;
@@ -530,32 +680,39 @@ sub post_line
 
 sub handle_fh
 {
-       my $in_fh = shift;
-       my $out_fh = shift;
+  my $in_fh = shift;
+  my $out_fh = shift;
 
-       set_output ($out_fh);
+  set_output ($out_fh);
 
-       if (@$InDS)
-       {
-         add_handler (\&handle_line_dsmap);
-       }
+  if (@$InDS)
+  {
+    add_handler (\&handle_line_dsmap);
+  }
 
-       if ($Step)
-       {
-         add_handler (\&handle_line_step);
-       }
+  if ($Step)
+  {
+    add_handler (\&handle_line_step);
+  }
 
-       if (@$NewRRAs)
-       {
-         add_handler (\&handle_line_add_rra);
-       }
+  if (($Scale != 1.0) || ($Shift != 0.0))
+  {
+    add_handler (\&handle_line_scale_shift);
+  }
 
-       add_handler (\&handle_line_output);
+  #add_handler (\&handle_line_peak_detect);
 
-       while (my $line = <$in_fh>)
-       {
-               post_line ($line, 0);
-       }
+  if (@$NewRRAs)
+  {
+    add_handler (\&handle_line_add_rra);
+  }
+
+  add_handler (\&handle_line_output);
+
+  while (my $line = <$in_fh>)
+  {
+    post_line ($line, 0);
+  }
 } # handle_fh
 
 sub main