summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 56e51b9)
raw | patch | inline | side by side (parent: 56e51b9)
author | Sebastian Harl <sh@tokkee.org> | |
Fri, 21 Nov 2014 20:23:57 +0000 (21:23 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Fri, 21 Nov 2014 20:23:57 +0000 (21:23 +0100) |
The graph will be displayed when querying a metric. The graph itself mostly
uses default settings of the Plotinum package for now.
uses default settings of the Plotinum package for now.
server/graph.go | [new file with mode: 0644] | patch | blob |
server/server.go | patch | blob | history | |
templates/metric.tmpl | patch | blob | history |
diff --git a/server/graph.go b/server/graph.go
--- /dev/null
+++ b/server/graph.go
@@ -0,0 +1,105 @@
+//
+// Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package server
+
+// Helper functions for handling and plotting graphs.
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "time"
+
+ "code.google.com/p/plotinum/plot"
+ "code.google.com/p/plotinum/plotter"
+ "code.google.com/p/plotinum/plotutil"
+ "code.google.com/p/plotinum/vg"
+ "code.google.com/p/plotinum/vg/vgsvg"
+ "github.com/sysdb/go/proto"
+ "github.com/sysdb/go/sysdb"
+)
+
+func (s *Server) graph(w http.ResponseWriter, req request) {
+ if len(req.args) < 2 {
+ s.internal(w, fmt.Errorf("Missing host/metric information"))
+ }
+
+ host := proto.EscapeString(req.args[0])
+ metric := proto.EscapeString(strings.Join(req.args[1:], "/"))
+ res, err := s.query(fmt.Sprintf("TIMESERIES %s.%s", host, metric))
+ if err != nil {
+ s.internal(w, fmt.Errorf("Failed to retrieve graph data: %v", err))
+ return
+ }
+
+ ts, ok := res.(sysdb.Timeseries)
+ if !ok {
+ s.internal(w, errors.New("TIMESERIES did not return a time-series"))
+ return
+ }
+
+ p, err := plot.New()
+ if err != nil {
+ s.internal(w, fmt.Errorf("Failed to create plot: %v", err))
+ return
+ }
+ p.Add(plotter.NewGrid())
+
+ var i int
+ for name, data := range ts.Data {
+ pts := make(plotter.XYs, len(data))
+ for i, p := range data {
+ pts[i].X = float64(time.Time(p.Timestamp).UnixNano())
+ pts[i].Y = p.Value
+ }
+ l, err := plotter.NewLine(pts)
+ if err != nil {
+ s.internal(w, fmt.Errorf("Failed to create line plotter: %v", err))
+ return
+ }
+ l.LineStyle.Color = plotutil.DarkColors[i%len(plotutil.DarkColors)]
+ p.Add(l)
+ p.Legend.Add(name, l)
+ i++
+ }
+
+ c := vgsvg.New(vg.Length(500), vg.Length(200))
+ p.Draw(plot.MakeDrawArea(c))
+
+ var buf bytes.Buffer
+ if _, err := c.WriteTo(&buf); err != nil {
+ s.internal(w, fmt.Errorf("Failed to write plot: %v", err))
+ return
+ }
+ w.Header().Set("Content-Type", "image/svg+xml")
+ w.WriteHeader(http.StatusOK)
+ io.Copy(w, &buf)
+}
+
+// vim: set tw=78 sw=4 sw=4 noexpandtab :
diff --git a/server/server.go b/server/server.go
index 33a2536f3b6fd491604cea59dbde8099460d91cc..59c1e4215a468bea1a3a36813eafc97014bfac99 100644 (file)
--- a/server/server.go
+++ b/server/server.go
s.mux = map[string]handler{
"images": s.static,
"style": s.static,
+ "graph": s.graph,
}
return s, nil
}
var host sysdb.Host
err = proto.Unmarshal(m, &host)
res = host
+ case proto.Timeseries:
+ var ts sysdb.Timeseries
+ err = proto.Unmarshal(m, &ts)
+ res = ts
default:
return nil, fmt.Errorf("Unsupported data type %d", t)
}
diff --git a/templates/metric.tmpl b/templates/metric.tmpl
index e4a0efb7c7417d75a621564f0ef69ea36a02593f..a2648017ec47b18e2678dc03979e33a832b245be 100644 (file)
--- a/templates/metric.tmpl
+++ b/templates/metric.tmpl
<section>{{$m := index .Metrics 0}}
<h1>Metric {{$.Name}} — {{$m.Name}}</h1>
+ <img src="/graph/{{urlquery $.Name}}/{{urlquery $m.Name}}" border="0" />
<table class="results">
<tr><td><b>Host</b></td><td><a href="/host/{{urlquery $.Name}}">{{$.Name}}</a></td></tr>
<tr><td><b>Last update</b></td><td>{{$m.LastUpdate}}</td></tr>