Giter Site home page Giter Site logo

raintank / grafana Goto Github PK

View Code? Open in Web Editor NEW

This project forked from grafana/grafana

42.0 28.0 4.0 110.22 MB

Grafana - A Graphite & InfluxDB Dashboard and Graph Editor

Home Page: http://grafana.org

License: Other

Shell 3.66% Go 78.82% HTML 17.28% Ruby 0.25%

grafana's Introduction

grafana's People

Contributors

acedrew avatar aheinz-sg avatar bleskes avatar bobrik avatar bruce-lyft avatar bulletfactory avatar ctdk avatar dewski avatar dieterbe avatar espenfjo avatar fg2it avatar frogmaster avatar jimmidyson avatar jwilder avatar masaori335 avatar mattttt avatar mavimo avatar mtanda avatar nikicat avatar nopzor1200 avatar polyfractal avatar spenceralger avatar splaspood avatar thuck avatar tmonk42 avatar toni-moreno avatar torkelo avatar utkarshcmu avatar williamjoy avatar woodsaj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grafana's Issues

Dashboard-based navigation between "related" dashboards

This was discussed before and during the summit.

We need a way to provide navigation to related dashboards without having to go to the big Dashboard picker. When we distribute bundles of related dashboards, this becomes very necessary (as it is for Litmus).

This has been requested a few times within the Grafana community.

Possibility of links in top bar? grafana#572

Navigation Panel Type grafana#517

Table of Contents and hierarchy for nav grafana#1378

Linked dashboards: grafana#1617

How should we do this?

Interim plan vs long term? HTML panel with static links?

Dashboards incorrectly prompt to Save

Currently whenever you edit the template variables in raintank Dashboards, and then try to navigate away from the Dashboard, you get the "Dashboard has changed" warning modal, even though there has been no changes to the Dashboard.

This likely needs to be a Grafana fix.

more endpoint dashboard tweaks

in rt-endpoint-ping dashboard:
in the ping response range panel:

  • add consolidateby(max) to max ping latency metric
  • add consolidateby(min) to min ping latency metric

in all dashboards:
in the status bar panel:

  • add consolidateby(sum) to all metrics

track internal (gauge) metrics?

i want to track the number of items in the internal alerting dispatch queue (basically len(channel))
what would be the best way to do this? i know we have an internal fork of the go-metrics library but it only seems to support gauges.

show litmus dashboards in dash search/list

litmus dashboards are served by a specialized dashboard controller that loads the dashboards directly from the server. this is pretty much how the DashFromFile controller works except the path to the dashboards is different.

Because these dashboards are not stored in the DB, they do not show up in the dashboards search/list menu.

Initial endpoint dashboard creation

Need initial versions of the following Dashboards created. These will be the "stock" (and non editable) Dashboards that will ship with Litmus.

· Endpoint Summary (attempted)
· Endpoint DNS (attempted)
· Endpoint PING (attempted)
· Endpoint WEB (attempted)
· Collector Summary
· Collector DNS
· Collector PING
· Collector WEB
· Events

Collector List language (configure, edit)

In the elipses menu, you can "edit" a Collector but in the detail view, the tab says "Configuration".

Let's standardize on "configure" and "configuration" as what you do to a Collector, and make no mention to "edit" or "editing"

"unexpected error" when trying to publish snapshot from litmus dashboard

i'm at https://portal.raintank.io/dashboard/raintank/rt-endpoint-web?var-endpoint=dieter_plaetinck_be&var-collector=All&var-protocol=http

i hit share->snapshot-> publish to snapshot.raintank.io
in network tab i see 4 /render calls, they all succeed
then in console i see

Exception { message: "", result: 2153644038, name: "", filename: "https://portal.raintank.io/app/app.02839f86.js", lineNumber: 12, columnNumber: 0, inner: null, data: null, stack: "kb/<@https://portal.raintank.io/app/app.02839f86.js:12:15874
v@https://portal.raintank.io/app/app.02839f86.js:12:14414
o/j@https://portal.raintank.io/app/app.02839f86.js:12:12985
i@https://portal.raintank.io/app/app.02839f86.js:12:29947
j/<@https://portal.raintank.io/app/app.02839f86.js:12:30119
Rb/this.$get</l.prototype.$eval@https://portal.raintank.io/app/app.02839f86.js:14:5281
Rb/this.$get</l.prototype.$digest@https://portal.raintank.io/app/app.02839f86.js:14:3795
Rb/this.$get</l.prototype.$apply@https://portal.raintank.io/app/app.02839f86.js:14:5539
f/j<@https://portal.raintank.io/app/app.02839f86.js:14:12796
g@https://portal.raintank.io/app/app.02839f86.js:11:23976
Ta/m.defer/c<@https://portal.raintank.io/app/app.02839f86.js:11:25978
" }
Exception { message: "", result: 2153644038, name: "", filename: "https://portal.raintank.io/app/app.02839f86.js", lineNumber: 12, columnNumber: 0, inner: null, data: null, stack: "kb/<@https://portal.raintank.io/app/app.02839f86.js:12:15874
v@https://portal.raintank.io/app/app.02839f86.js:12:14414
o/j@https://portal.raintank.io/app/app.02839f86.js:12:12985
i@https://portal.raintank.io/app/app.02839f86.js:12:29947
j/<@https://portal.raintank.io/app/app.02839f86.js:12:30119
Rb/this.$get</l.prototype.$eval@https://portal.raintank.io/app/app.02839f86.js:14:5281
Rb/this.$get</l.prototype.$digest@https://portal.raintank.io/app/app.02839f86.js:14:3795
Rb/this.$get</l.prototype.$apply@https://portal.raintank.io/app/app.02839f86.js:14:5539
f/j<@https://portal.raintank.io/app/app.02839f86.js:14:12796
g@https://portal.raintank.io/app/app.02839f86.js:11:23976
Ta/m.defer/c<@https://portal.raintank.io/app/app.02839f86.js:11:25978
" }
Object { message: "Unexpected error", severity: "error" } app.02839f86.js:12:24598
e/<() app.02839f86.js:12
bb/this.$get</<() app.02839f86.js:12
f/j<() app.02839f86.js:14
g() app.02839f86.js:11
Ta/m.defer/c<() app.02839f86.js:11

Configure collector styling

When configuring a Collector, the styling in the top nav is not consistent with the rest of the interface (in the Collector dropdown).

automate creation of dashboards

We want users to automatically be provided with our stock dashboards for displaying the litmus data. These dashboards should only be added to organisations when there is data available to be displayed.
eg. When a user adds their first endpoint, the summary status dashboard should be added to their account. When they add their first Ping check, the Ping dashboard should be added.

Cannot rename collector

If you create a collector, save, then try and edit the name, it appears to rename successfully (w/ success message), but switches back to its original name.

Default Menu State: Open

For the raintank build, I'd like to side menu to be open for new users.

Unsure how state is set/saved (if it is), so this might need some quick discussion with @awoods or @torkelo

Managing (becoming) other organizations

The Grafana system admin should (I think) have some way of becoming or switching to any Organization that they want to.

This is necessary for supportability when a system admin is responsible for many Users across many Organizations.

helper Text in New Endpoint

When new Litmus users do not have any Endpoints added, it would be nice to give them some basic instructions on adding an Endpoint.

Here's some sample text that can be displayed if they don't have any Endpoints:

It looks like you don’t have any Endpoints yet.

Add an Endpoint to get started with raintank Litmus. An Endpoint can be anything you want to monitor.

When you add a domain name of your Endpoint, we will automatically detect what we can monitor (eg. PING, HTTP, HTTPS) and suggest a configuration that can be customized.

`Nullable: false, Default: ""`migration leads to column with null values

       mg.AddMigration("monitor add alerts v1", NewAddColumnMigration("monitor", &Column{
                Name: "health_settings", Type: DB_NVarchar, Length: 2048, Nullable: false, Default: "",
        }))

leads to this. note that the health_settings has NOT NULL set (good), but yet, a new column shows up with a null value?

mysql> select * from monitor\G
*************************** 1. row ***************************
             id: 1
    endpoint_id: 1
         org_id: 1
      namespace: dieter_plaetinck_be
monitor_type_id: 3
         offset: 5
      frequency: 10
        enabled: 1
       settings: [{"variable":"hostname","value":"dieter.plaetinck.be"}]
          state: 0
   state_change: 2015-05-12 19:05:24
        created: 2015-05-12 19:05:11
        updated: 2015-05-12 19:05:24
health_settings: null
1 row in set (0.00 sec)

mysql> show create table monitor;
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| monitor | CREATE TABLE `monitor` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `endpoint_id` bigint(20) NOT NULL,
  `org_id` bigint(20) NOT NULL,
  `namespace` varchar(255) NOT NULL,
  `monitor_type_id` bigint(20) NOT NULL,
  `offset` bigint(20) NOT NULL,
  `frequency` bigint(20) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  `settings` varchar(2048) NOT NULL,
  `state` bigint(20) NOT NULL,
  `state_change` datetime NOT NULL,
  `created` datetime NOT NULL,
  `updated` datetime NOT NULL,
  `health_settings` varchar(2048) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UQE_monitor_org_id_namespace_monitor_type_id` (`org_id`,`namespace`,`monitor_type_id`),
  KEY `IDX_monitor_monitor_type_id` (`monitor_type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>    

Collector List language (online, offline)

Keep language consistent.

We refer to collector status as "Online" or "Offline". The header for Collector List should be consistent with this, and changed from "UP|DOWN" to "Online|Offline"

local snapshots don't properly contain the needed the data

on https://portal.raintank.io/dashboard/raintank/rt-endpoint-web?var-endpoint=dieter_plaetinck_be&var-collector=All&var-protocol=http, with timepicker set from 7d ago to now

share->snapshot->local
first time i got this one:
https://portal.raintank.io/dashboard/snapshot/T1LGC84lhjusXNUUHctIOtbo63gI5xG9
note that one out of the four doesn't contain the needed data

then i tried again with firebug open, and got
https://portal.raintank.io/dashboard/snapshot/Cfck10A2wG8TfDDvfqRb1ukdXY9tgMXh
note that all 3 graphs don't work, only the errors panel works.

looking at network tab, i can see the 4 render requests all worked and returned proper json data,
however the first one (for ok/warning/...) returned in about a second, the other three took longer. maybe that's related.

here's what it posted to portal.raintank.io/api/snapshots:

{"dashboard":{"id":null,"title":"rt-endpoint-web","originalTitle":"rt-endpoint-web","tags":[],"style":"dark","timezone":"browser","editable":false,"hideControls":true,"sharedCrosshair":false,"rows":[{"collapse":false,"editable":true,"height":"20px","panels":[{"content":"<div style=\"margin-top: -15px;\">\n<div style=\"float: left;\"\n<small>\n<a href=\"/dashboard/raintank/rt-endpoint-summary?var-endpoint=$endpoint\">SUMMARY</a> | \n<a href=\"/dashboard/raintank/rt-endpoint-dns?var-endpoint=$endpoint\">DNS</a> | \n<a href=\"/dashboard/raintank/rt-endpoint-ping?var-endpoint=$endpoint\">PING</a> |\n<u><big><a href=\"/dashboard/raintank/rt-endpoint-web?var-endpoint=$endpoint&var-collector=$collector&var-protocol=http\">HTTP</a> |\n<a href=\"/dashboard/db/rt-endpoint-web?var-endpoint=$endpoint&var-collector=$collector&var-protocol=https\">HTTPS</a></big></u></small>\n</div>\n<div style=\"float: right;\">\n<small>(r) LITMUS (?)</small>\n</div>\n</div>","editable":true,"error":false,"id":585,"links":[],"mode":"html","span":12,"style":{},"title":"","transparent":true,"type":"text","targets":[],"datasource":null}],"title":"New row"},{"collapse":false,"editable":true,"height":"100px","panels":[{"aliasColors":{"error":"#BF1B00","ok":"#508642"},"bars":true,"datasource":null,"decimals":0,"editable":true,"error":false,"fill":1,"grid":{"leftLogBase":1,"leftMax":null,"leftMin":0,"rightLogBase":1,"rightMax":null,"rightMin":null,"threshold1":null,"threshold1Color":"rgba(216, 200, 27, 0.27)","threshold2":null,"threshold2Color":"rgba(234, 112, 112, 0.22)"},"height":"100","id":583,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":false,"linewidth":2,"links":[],"maxDataPoints":"100","nullPointMode":"connected","percentage":true,"pointradius":5,"points":false,"renderer":"flot","scopedVars":{},"seriesOverrides":[],"span":12,"stack":true,"steppedLine":false,"targets":[],"timeFrom":null,"timeShift":null,"title":"Status for $endpoint on $protocol (across all selected Collectors)","tooltip":{"shared":true,"value_type":"individual"},"transparent":true,"type":"graph","x-axis":true,"y-axis":false,"y_formats":["short","short"],"snapshotData":{"data":[{"target":"ok","datapoints":[[null,1430069106000],[null,1430075166000],[null,1430081226000],[null,1430087286000],[null,1430093346000],[null,1430099406000],[null,1430105466000],[null,1430111526000],[null,1430117586000],[null,1430123646000],[null,1430129706000],[null,1430135766000],[null,1430141826000],[null,1430147886000],[null,1430153946000],[null,1430160006000],[null,1430166066000],[null,1430172126000],[null,1430178186000],[null,1430184246000],[null,1430190306000],[null,1430196366000],[null,1430202426000],[null,1430208486000],[null,1430214546000],[null,1430220606000],[null,1430226666000],[null,1430232726000],[1,1430238786000],[1,1430244846000],[1,1430250906000],[1,1430256966000],[1,1430263026000],[1,1430269086000],[1,1430275146000],[1,1430281206000],[1,1430287266000],[1,1430293326000],[1,1430299386000],[1,1430305446000],[1,1430311506000],[1,1430317566000],[1,1430323626000],[1,1430329686000],[1,1430335746000],[1,1430341806000],[1,1430347866000],[1,1430353926000],[1,1430359986000],[1,1430366046000],[1,1430372106000],[1,1430378166000],[1,1430384226000],[1,1430390286000],[1,1430396346000],[1,1430402406000],[1,1430408466000],[1,1430414526000],[1,1430420586000],[1,1430426646000],[1,1430432706000],[1,1430438766000],[1,1430444826000],[1,1430450886000],[1,1430456946000],[1,1430463006000],[1,1430469066000],[1,1430475126000],[1,1430481186000],[1,1430487246000],[1,1430493306000],[1,1430499366000],[1,1430505426000],[1,1430511486000],[1,1430517546000],[1,1430523606000],[1,1430529666000],[1,1430535726000],[1,1430541786000],[1,1430547846000],[1,1430553906000],[1,1430559966000],[1,1430566026000],[1,1430572086000],[1,1430578146000],[1,1430584206000],[1,1430590266000],[1,1430596326000],[1,1430602386000],[1,1430608446000],[1,1430614506000],[1,1430620566000],[1,1430626626000],[1,1430632686000],[1,1430638746000],[1,1430644806000],[1,1430650866000],[1,1430656926000],[1,1430662986000]]},{"target":"warn","datapoints":[[null,1430069106000],[null,1430075166000],[null,1430081226000],[null,1430087286000],[null,1430093346000],[null,1430099406000],[null,1430105466000],[null,1430111526000],[null,1430117586000],[null,1430123646000],[null,1430129706000],[null,1430135766000],[null,1430141826000],[null,1430147886000],[null,1430153946000],[null,1430160006000],[null,1430166066000],[null,1430172126000],[null,1430178186000],[null,1430184246000],[null,1430190306000],[null,1430196366000],[null,1430202426000],[null,1430208486000],[null,1430214546000],[null,1430220606000],[null,1430226666000],[null,1430232726000],[0,1430238786000],[0,1430244846000],[0,1430250906000],[0,1430256966000],[0,1430263026000],[0,1430269086000],[0,1430275146000],[0,1430281206000],[0,1430287266000],[0,1430293326000],[0,1430299386000],[0,1430305446000],[0,1430311506000],[0,1430317566000],[0,1430323626000],[0,1430329686000],[0,1430335746000],[0,1430341806000],[0,1430347866000],[0,1430353926000],[0,1430359986000],[0,1430366046000],[0,1430372106000],[0,1430378166000],[0,1430384226000],[0,1430390286000],[0,1430396346000],[0,1430402406000],[0,1430408466000],[0,1430414526000],[0,1430420586000],[0,1430426646000],[0,1430432706000],[0,1430438766000],[0,1430444826000],[0,1430450886000],[0,1430456946000],[0,1430463006000],[0,1430469066000],[0,1430475126000],[0,1430481186000],[0,1430487246000],[0,1430493306000],[0,1430499366000],[0,1430505426000],[0,1430511486000],[0,1430517546000],[0,1430523606000],[0,1430529666000],[0,1430535726000],[0,1430541786000],[0,1430547846000],[0,1430553906000],[0,1430559966000],[0,1430566026000],[0,1430572086000],[0,1430578146000],[0,1430584206000],[0,1430590266000],[0,1430596326000],[0,1430602386000],[0,1430608446000],[0,1430614506000],[0,1430620566000],[0,1430626626000],[0,1430632686000],[0,1430638746000],[0,1430644806000],[0,1430650866000],[0,1430656926000],[0,1430662986000]]},{"target":"error","datapoints":[[null,1430069106000],[null,1430075166000],[null,1430081226000],[null,1430087286000],[null,1430093346000],[null,1430099406000],[null,1430105466000],[null,1430111526000],[null,1430117586000],[null,1430123646000],[null,1430129706000],[null,1430135766000],[null,1430141826000],[null,1430147886000],[null,1430153946000],[null,1430160006000],[null,1430166066000],[null,1430172126000],[null,1430178186000],[null,1430184246000],[null,1430190306000],[null,1430196366000],[null,1430202426000],[null,1430208486000],[null,1430214546000],[null,1430220606000],[null,1430226666000],[null,1430232726000],[0,1430238786000],[0,1430244846000],[0,1430250906000],[0.009900990099009901,1430256966000],[0.009900990099009901,1430263026000],[0,1430269086000],[0,1430275146000],[0.05102040816326531,1430281206000],[0,1430287266000],[0,1430293326000],[0,1430299386000],[0,1430305446000],[0,1430311506000],[0,1430317566000],[0,1430323626000],[0.009900990099009901,1430329686000],[0,1430335746000],[0,1430341806000],[0,1430347866000],[0,1430353926000],[0,1430359986000],[0,1430366046000],[0,1430372106000],[0,1430378166000],[0,1430384226000],[0,1430390286000],[0,1430396346000],[0,1430402406000],[0,1430408466000],[0,1430414526000],[0,1430420586000],[0,1430426646000],[0,1430432706000],[0,1430438766000],[0,1430444826000],[0,1430450886000],[0,1430456946000],[0,1430463006000],[0,1430469066000],[0,1430475126000],[0,1430481186000],[0,1430487246000],[0,1430493306000],[0,1430499366000],[0,1430505426000],[0,1430511486000],[0,1430517546000],[0,1430523606000],[0,1430529666000],[0,1430535726000],[0,1430541786000],[0,1430547846000],[0,1430553906000],[0,1430559966000],[0,1430566026000],[0,1430572086000],[0,1430578146000],[0,1430584206000],[0,1430590266000],[0,1430596326000],[0,1430602386000],[0,1430608446000],[0.009900990099009901,1430614506000],[0,1430620566000],[0,1430626626000],[0,1430632686000],[0,1430638746000],[0,1430644806000],[0,1430650866000],[0,1430656926000],[0,1430662986000]]}],"status":200,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"url":"/api/graphite/render","data":"target=alias(maxSeries(dieter_plaetinck_be.%7Bamsterdam%2Cfrankfurt%2Clondon%2Cnew-jersey%2Cnew-york%2Cparis%2Csan-francisco%2Cseattle%2Csingapore%2Ctokyo%7D.network.http.ok_state)%2C%20'ok')&target=alias(maxSeries(dieter_plaetinck_be.%7Bamsterdam%2Cfrankfurt%2Clondon%2Cnew-jersey%2Cnew-york%2Cparis%2Csan-francisco%2Cseattle%2Csingapore%2Ctokyo%7D.network.http.warn_state)%2C%20'warn')&target=alias(maxSeries(dieter_plaetinck_be.%7Bamsterdam%2Cfrankfurt%2Clondon%2Cnew-jersey%2Cnew-york%2Cparis%2Csan-francisco%2Cseattle%2Csingapore%2Ctokyo%7D.network.http.error_state)%2C%20'error')&from=-7d&until=now&format=json&maxDataPoints=100","headers":{"Content-Type":"application/x-www-form-urlencoded","Accept":"application/json, text/plain, */*"},"inspect":{"type":"graphite"},"retry":0},"statusText":"OK"}}],"title":"New row"},{"collapse":false,"editable":true,"height":"250px","panels":[{"aliasColors":{"connect":"#508642","dns":"#0A50A1","recv":"#BA43A9","send":"#1F78C1","wait":"#EA6460"},"bars":false,"datasource":null,"editable":true,"error":false,"fill":1,"grid":{"leftLogBase":1,"leftMax":null,"leftMin":0,"rightLogBase":1,"rightMax":null,"rightMin":0,"threshold1":null,"threshold1Color":"rgba(216, 200, 27, 0.27)","threshold2":null,"threshold2Color":"rgba(234, 112, 112, 0.22)"},"height":"250","id":584,"leftYAxisLabel":"latency","legend":{"alignAsTable":false,"avg":false,"current":false,"max":false,"min":false,"rightSide":false,"show":true,"total":false,"values":false},"lines":false,"linewidth":2,"links":[],"maxDataPoints":"150","nullPointMode":"null","percentage":false,"pointradius":1,"points":true,"renderer":"flot","scopedVars":{},"seriesOverrides":[{"alias":"download speed","bars":false,"fill":0,"lines":true,"points":false,"yaxis":2}],"span":6,"stack":true,"steppedLine":false,"targets":[],"timeFrom":null,"timeShift":null,"title":"$protocol performance for $endpoint (avg of selected Collectors)","tooltip":{"shared":true,"value_type":"individual"},"type":"graph","x-axis":true,"y-axis":true,"y_formats":["bytes","Bps"]},{"aliasColors":{"connect":"#508642","dns":"#0A50A1","recv":"#BA43A9","send":"#1F78C1","wait":"#EA6460"},"bars":true,"datasource":null,"editable":true,"error":false,"fill":2,"grid":{"leftLogBase":1,"leftMax":null,"leftMin":0,"rightLogBase":1,"rightMax":null,"rightMin":null,"threshold1":null,"threshold1Color":"rgba(216, 200, 27, 0.27)","threshold2":null,"threshold2Color":"rgba(234, 112, 112, 0.22)"},"height":"250","id":579,"leftYAxisLabel":"latency","legend":{"alignAsTable":false,"avg":false,"current":false,"max":false,"min":false,"rightSide":false,"show":true,"total":false,"values":false},"lines":false,"linewidth":2,"links":[],"maxDataPoints":"100","nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","scopedVars":{},"seriesOverrides":[{"alias":"throughput","bars":false,"fill":0,"lines":true,"yaxis":2}],"span":6,"stack":true,"steppedLine":false,"targets":[],"timeFrom":null,"timeShift":null,"title":"$protocol response for $endpoint (avg of selected Collectors)","tooltip":{"shared":true,"value_type":"individual"},"type":"graph","x-axis":true,"y-axis":true,"y_formats":["ms","Bps"]}],"title":"New row"},{"collapse":false,"editable":true,"height":"250px","panels":[{"aliasColors":{"connect":"#0A50A1","dns":"#890F02","recv":"#6ED0E0","send":"#508642","wait":"#EAB839"},"bars":false,"datasource":null,"editable":true,"error":false,"fill":0,"grid":{"leftLogBase":1,"leftMax":null,"leftMin":null,"rightLogBase":1,"rightMax":null,"rightMin":null,"threshold1":null,"threshold1Color":"rgba(216, 200, 27, 0.27)","threshold2":null,"threshold2Color":"rgba(234, 112, 112, 0.22)"},"height":"500","id":581,"leftYAxisLabel":"latency","legend":{"alignAsTable":true,"avg":true,"current":true,"max":false,"min":false,"rightSide":false,"show":true,"sort":"current","sortDesc":true,"total":false,"values":true},"lines":false,"linewidth":2,"links":[],"maxDataPoints":"350","nullPointMode":"null","percentage":false,"pointradius":2,"points":true,"renderer":"flot","scopedVars":{},"seriesOverrides":[],"span":12,"stack":false,"steppedLine":false,"targets":[],"timeFrom":null,"timeShift":null,"title":"$protocol response total for $endpoint (each selected Collectors)","tooltip":{"shared":true,"value_type":"individual"},"type":"graph","x-axis":true,"y-axis":true,"y_formats":["ms","short"]}],"repeat":"$endpoint","title":"Row"}],"nav":[{"collapse":false,"enable":true,"notice":false,"now":true,"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"status":"Stable","time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"],"type":"timepicker"}],"time":{"from":"2015-04-26T15:47:57.038Z","to":"2015-05-03T15:47:57.038Z"},"templating":{"list":[{"allFormat":"glob","datasource":null,"includeAll":false,"label":"Endpoint(s)","multi":false,"multiFormat":"glob","name":"endpoint","options":[],"query":"","refresh":false,"refresh_on_load":false,"type":"query","current":{"text":"dieter_plaetinck_be","value":"dieter_plaetinck_be"}},{"allFormat":"glob","datasource":null,"includeAll":true,"label":"Collector(s)","multi":true,"multiFormat":"glob","name":"collector","options":[],"query":"","refresh":false,"refresh_on_load":true,"type":"query","current":{"text":"All","value":"{amsterdam,frankfurt,london,new-jersey,new-york,paris,san-francisco,seattle,singapore,tokyo}"}},{"allFormat":"glob","current":{"selected":true,"text":"http","value":"http"},"datasource":null,"includeAll":false,"label":"protocol","multi":false,"multiFormat":"glob","name":"protocol","options":[],"query":"","refresh_on_load":false,"type":"custom","refresh":false}]},"annotations":{"list":[]},"refresh":false,"snapshot":{"timestamp":"2015-05-03T15:47:53.031Z"},"schemaVersion":6,"version":21},"expires":0}

wire up Collector tag dashboards

The links to dashboards-by-Collector-tag are dead.

Please wire up multiselect links for the list of Collectors in that tag.

We might use existing endpoint dashboard or create another dashboard for this. Still thinking about it. Important thing is that we can link to dashboard?var-collector= but with the Tag values instead of an individual Collector, and leverage the template multiselect now in Grafana.

New Endpoint Page Adjustments

Checklist for help from AWoods:

  • Trigger Spinner on "Auto-Discover"
  • Wire up New Endpoint page to New Endpoint button.
  • Change options in Frequency Select Box to "Every 10s, Every 30s..."
  • New resting state & disabled state.
  • Issue with Enabled button not being checked in both places.
  • Enabled button collapsing the box.
  • Collector select button showing results in a select Box.
  • Wire up Add Endpoint & Cancel buttons.

alert scheduling, modulo, modulo offset

Torkel and I decided it makes a lot of sense for initial alerting implementation to just query the monitor table, since the up/down definition is now a rule that is very closely tied to the monitor definition, and will in fact be stored in the monitor table along with the other check parameters. So no need to manage alerting rules in a separate alerting table.
For the alert scheduling, 3 parameters are very important:

  • frequency should be in sync with data collection. i.e. if a check runs every 10 seconds, so should the alert/health-indicator-updator. this is easy, as there is a frequency column in the monitor table already
  • when within each period should be the alert trigger? For a given customer all collectors will run at the same time right? And does that go for all checks for a given customer? it looks like it's not the case ( if that's what the monitor.offset column is), let me explain what I mean:
    if I have dns check every 60 sec and http check every 10 sec, then i would say my customer id should be hashed and modulo'd by 60, let's say the result is 37, and then that module 10 is 7,
    this means the minutely check runs at every minute and 37 seconds, while every 10-second runs at min:07, min:17, min:27,min:37 and so on. the advantage is that even for different frequencies, the point's timing still match up. I think this will become useful later in alerting logic that looks at different series for the same endpoint but where data which is at different resolutions. otherwise scenarios where the minutely check runs at 0:37 and the 10-secondly runs at 0:32 and 0:42 could be very ambiguous and hard to relate. (although admittedly this is not much more than some gut feeling)

anyway my point is in models/monitor.go i saw these 2 fields and i was wondering if modulo == frequency and modulooffset == seconds to wait at the start of each interval?

174   Modulo         int64   `form:"modulo"`
175   ModuloOffset   int64   `form:"modulo_offset"` 

i think the best approach would be just hashing customer id to a number, and then storing that number, so you can easily query for the appropriate scheduling offset like so:

select hashed_number % frequency as offset, frequency from monitor

(modulo is supported by both mysql and sqlite)
the advantage is we don't lock ourself into any timeframe.
let's say we later decide to support 10-minutely, then we can always easily retrieve the proper offset that also syncs up with higher-frequency periods.

anyway the alerting logic has to query the offset somehow

  1. we should maintain a special offset variable that tells how long it takes from the collector data to make it into the system and the data to become available for querying, and then some extra time to be safe.
    so that we can schedule the alert shortly after the data arriving into the system, but also not too late.
    i presume one global variable should be enough to cover all customers and all collectors, where-ever they are? i can imagine later we may implement a service that taps into the stream and keeps tabs on the per-collector delays or continuously queries graphite-api and adjusts this offset automatically.

can't easily find configuration for, say, http check

i have only 1 endpoint and i want to modify the http check config
i have to go to endpoints, select my endpoint and then go to configuration
this is confusing to me because when i think "i want to change my http check config" i really don't think about going to endpoints, especially since I'm a customer who only monitors one site so i don't even think of the concept of endpoints anymore. note that #55 might alleviate this but i wonder if we can perhaps have a side entry "checks" from which i can easily go to my http check config

panel-based navigation

Many dashboards will show summaries of a particular endpoint or collection, it is important that users are able to click a panel to go to another dashboard / set template variables.

For Litmus, we want to be able to navigate to a given Dashboard with a given set of template variables by clicking on a particular panel.

This feature has already been discussed at length by the Grafana community, and some functionality exists within Grafana to help accomplish it:

links to other dashboards grafana#1041

Make Drill­down easier grafana#1575

Whole panel clickable grafana#1377

Drilldown graph link grafana#1232

Event panel parameters

Event panel should be able to accept the $endpoint and $collector variables as arguments (set in Grafana Templates). Should be able to accept single vals (ie. "foo") or Graphite-style globs (ie "{foo,bar,moo}")

Definitely open to accomplishing this some other way but this seemed logical. This will allow it to function with the same filters as the rest of the Dashboards.

Need better control over Input Length, Order and other elements of Endpoint Check Fields

Currently the new & edit endpoint are programmatically getting all the fields from the backend, but I'm not able to see where I have individual control over input lengths and order.

<div class="editor-option rt-input-styles" style="padding-top: 15px; padding-bottom: 5px; width: auto;     height: auto;" ng-repeat="setting in monitor_types_by_name['ping'].settings">
<raintank-setting definition="setting" target="currentSettingByVariable(monitors['ping'], setting.variable)">
</div>

I was going to just try and break out the individual elements and recreate the forms manually, but that seemed silly. Im sure there's a more centralized way to achieve this.

We can also chat about additional features, but this is a good start.

feedback link no longer works

In tinyalpha the feedback link in the bottom is no longer persistent, and when i can catch it it no longer works.

raintank-icons missing

recent changes depend on fonts/raintank-icons.(ttf, eot, woff, svg) but these have not been committed.

users resetting password

(I don't think this is raintank specific but opening here)

There needs to be a way for users to reset their passwords in Grafana.

Currently this is impossible (I think). Only the admin can do this.

tracking important errors

do we have any convention on how we will keep tabs on critical/important error events in grafana?
maybe log to a file and then use heka or logstash to shove them into ES?

datarace in websocket code

once in a while, it's useful to bulid with go build -race and see if anything shows up at runtime.
and something did. a non-threadsafe datastructure is being read from and written to at the same time.

creating new InProcBus
sqlstore/monitor adding bus handlers...
sqlstore/monitor adding bus handlers done
creating new InProcBus
2015/05/12 20:13:26 �[1;32m[I] Starting Grafana�[0m
2015/05/12 20:13:26 �[1;32m[I] Version: master, Commit: NA, Build date: 1970-01-01 00:00:00 +0000 UTC�[0m
2015/05/12 20:13:26 �[1;32m[I] Configuration Info
Config files:
  [0]: /go/src/github.com/grafana/grafana/conf/defaults.ini
  [1]: /go/src/github.com/grafana/grafana/conf/custom.ini
Paths:
  home: /go/src/github.com/grafana/grafana
  data: /go/src/github.com/grafana/grafana/data
  logs: /go/src/github.com/grafana/grafana/data/log
�[0m
2015/05/12 20:13:26 �[1;32m[I] Database: mysql, ConnectionString: grafana:password@tcp(mysql:3306)/grafana?charset=utf8�[0m
2015/05/12 20:13:26 �[1;32m[I] Migrator: Starting DB migration�[0m
dispatching msgName GetSystemStatsQuery
dispatching msgName ClearCollectorSessionCommand
2015/05/12 20:13:26 �[1;32m[I] Listen: http://0.0.0.0:80�[0m
attempting dispatch 2015-05-12 20:13:27.000135748 +0000 UTC
2015-05-12 20:13:27.000135748 +0000 UTC querying for jobs that should run in second 1431461607
>getSchedules() dispatching GetMonitorsQuery
dispatching msgName GetMonitorsQuery
handler not found for  GetMonitorsQuery
>getSchedules() got error! handler not found
attempting dispatch 2015-05-12 20:13:28.000157702 +0000 UTC
2015-05-12 20:13:28.000157702 +0000 UTC querying for jobs that should run in second 1431461608
>getSchedules() dispatching GetMonitorsQuery
dispatching msgName GetMonitorsQuery
handler not found for  GetMonitorsQuery
>getSchedules() got error! handler not found
2015/05/12 20:13:28 http: response.WriteHeader on hijacked connection
dispatching msgName GetApiKeyByNameQuery
2015/05/12 20:13:28 �[1;32m[I] Completed /socket.io/ 400 Bad Request in 2.321553ms�[0m
attempting dispatch 2015-05-12 20:13:29.000060672 +0000 UTC
2015-05-12 20:13:29.000060672 +0000 UTC querying for jobs that should run in second 1431461609
>getSchedules() dispatching GetMonitorsQuery
dispatching msgName GetMonitorsQuery
handler not found for  GetMonitorsQuery
>getSchedules() got error! handler not found
dispatching msgName GetCollectorByNameQuery
dispatching msgName AddCollectorSessionCommand
2015/05/12 20:13:29 �[1;32m[I] New connection for PublicTest owned by OrgId: 1�[0m
dispatching msgName GetCollectorSessionsQuery
2015/05/12 20:13:29 �[1;32m[I] Collector 1 refreshing�[0m
searching for sessions for collector 1
dispatching msgName GetMonitorsQuery
handler found for  GetMonitorsQuery
2015/05/12 20:13:29 �[1;32m[I] sending refresh to BW-AAaHZHL7_yGqCXWwS�[0m
attempting dispatch 2015-05-12 20:13:30.000096116 +0000 UTC
2015-05-12 20:13:30.000096116 +0000 UTC querying for jobs that should run in second 1431461610
>getSchedules() dispatching GetMonitorsQuery
dispatching msgName GetMonitorsQuery
handler not found for  GetMonitorsQuery
>getSchedules() got error! handler not found
2015/05/12 20:13:30 http: response.WriteHeader on hijacked connection
2015/05/12 20:13:30 �[1;32m[I] Completed /socket.io/ 400 Bad Request in 1.055798ms�[0m
dispatching msgName GetApiKeyByNameQuery
attempting dispatch 2015-05-12 20:13:31.000057145 +0000 UTC
2015-05-12 20:13:31.000057145 +0000 UTC querying for jobs that should run in second 1431461611
>getSchedules() dispatching GetMonitorsQuery
dispatching msgName GetMonitorsQuery
handler not found for  GetMonitorsQuery
>getSchedules() got error! handler not found
dispatching msgName GetCollectorByNameQuery
dispatching msgName AddCollectorSessionCommand
2015/05/12 20:13:31 �[1;32m[I] New connection for PublicTest owned by OrgId: 1�[0m
dispatching msgName GetCollectorSessionsQuery
searching for sessions for collector 1
2015/05/12 20:13:31 �[1;32m[I] Collector 1 refreshing�[0m
dispatching msgName GetMonitorsQuery
handler found for  GetMonitorsQuery
2015/05/12 20:13:31 �[1;32m[I] sending refresh to BW-AAaHZHL7_yGqCXWwS�[0m
==================
WARNING: DATA RACE
Read by goroutine 40:
  github.com/gorilla/websocket.(*Conn).NextWriter()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:311 +0x65
  github.com/googollee/go-engine.io/websocket.(*Server).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/websocket/server.go:44 +0xbe
  github.com/googollee/go-engine%2eio.(*serverConn).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/server_conn.go:150 +0xd1
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:93 +0x9a
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Previous write by goroutine 36:
  github.com/gorilla/websocket.(*Conn).flushFrame()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:384 +0x9e3
  github.com/gorilla/websocket.messageWriter.Close()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:504 +0x122
  github.com/gorilla/websocket.(*messageWriter).Close()
      <autogenerated>:7 +0xd5
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Close()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:114 +0x81
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x89f
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Goroutine 40 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187

Goroutine 36 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187
==================
==================
WARNING: DATA RACE
Read by goroutine 40:
  github.com/gorilla/websocket.(*Conn).NextWriter()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:315 +0xd0
  github.com/googollee/go-engine.io/websocket.(*Server).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/websocket/server.go:44 +0xbe
  github.com/googollee/go-engine%2eio.(*serverConn).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/server_conn.go:150 +0xd1
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:93 +0x9a
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Previous write by goroutine 36:
  github.com/gorilla/websocket.(*Conn).flushFrame()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:388 +0xa52
  github.com/gorilla/websocket.messageWriter.Close()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:504 +0x122
  github.com/gorilla/websocket.(*messageWriter).Close()
      <autogenerated>:7 +0xd5
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Close()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:114 +0x81
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x89f
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Goroutine 40 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187

Goroutine 36 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187
==================
==================
WARNING: DATA RACE
Read by goroutine 40:
  github.com/gorilla/websocket.(*Conn).NextWriter()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:326 +0x227
  github.com/googollee/go-engine.io/websocket.(*Server).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/websocket/server.go:44 +0xbe
  github.com/googollee/go-engine%2eio.(*serverConn).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/server_conn.go:150 +0xd1
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:93 +0x9a
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Previous write by goroutine 36:
  github.com/gorilla/websocket.(*Conn).flushFrame()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:390 +0xa99
  github.com/gorilla/websocket.messageWriter.Close()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:504 +0x122
  github.com/gorilla/websocket.(*messageWriter).Close()
      <autogenerated>:7 +0xd5
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Close()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:114 +0x81
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x89f
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Goroutine 40 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187

Goroutine 36 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187
==================
==================
WARNING: DATA RACE
Read by goroutine 40:
  github.com/gorilla/websocket.messageWriter.ncopy()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:413 +0x71
  github.com/gorilla/websocket.messageWriter.write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:442 +0x28f
  github.com/gorilla/websocket.messageWriter.Write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:454 +0x7d
  github.com/gorilla/websocket.(*messageWriter).Write()
      <autogenerated>:4 +0xf9
  github.com/googollee/go-engine.io/parser.newEncoder()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:80 +0xc7
  github.com/googollee/go-engine.io/parser.NewStringEncoder()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:71 +0x7c
  github.com/googollee/go-engine.io/websocket.(*Server).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/websocket/server.go:48 +0x16f
  github.com/googollee/go-engine%2eio.(*serverConn).NextWriter()
      /home/dieter/go/src/github.com/googollee/go-engine.io/server_conn.go:150 +0xd1
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:93 +0x9a
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Previous write by goroutine 36:
  github.com/gorilla/websocket.(*Conn).flushFrame()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:387 +0xa34
  github.com/gorilla/websocket.messageWriter.Close()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:504 +0x122
  github.com/gorilla/websocket.(*messageWriter).Close()
      <autogenerated>:7 +0xd5
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Close()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:114 +0x81
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x89f
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Goroutine 40 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187

Goroutine 36 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187
==================
==================
WARNING: DATA RACE
Write by goroutine 40:
  runtime.slicecopy()
      /build/go/src/go-1.4.2/src/runtime/slice.go:94 +0x0
  github.com/gorilla/websocket.messageWriter.write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:446 +0x3f1
  github.com/gorilla/websocket.messageWriter.Write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:454 +0x7d
  github.com/gorilla/websocket.(*messageWriter).Write()
      <autogenerated>:4 +0xf9
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Write()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:108 +0x97
  github.com/googollee/go-socket%2eio.(*trimWriter).Write()
      /home/dieter/go/src/github.com/googollee/go-socket.io/trim_writer.go:40 +0x524
  github.com/googollee/go-socket%2eio.(*writerHelper).Write()
      /home/dieter/go/src/github.com/googollee/go-socket.io/ioutil.go:23 +0xb5
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:101 +0x3d5
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Previous read by goroutine 36:
  syscall.raceReadRange()
      /build/go/src/go-1.4.2/src/syscall/race.go:25 +0x40
  syscall.Write()
      /build/go/src/go-1.4.2/src/syscall/syscall_unix.go:154 +0xb4
  net.(*netFD).Write()
      /build/go/src/go-1.4.2/src/net/fd_unix.go:327 +0x416
  net.(*conn).Write()
      /build/go/src/go-1.4.2/src/net/net.go:129 +0x124
  net.(*TCPConn).Write()
      <autogenerated>:37 +0x85
  github.com/gorilla/websocket.(*Conn).write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:230 +0x309
  github.com/gorilla/websocket.(*Conn).flushFrame()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:384 +0x9b2
  github.com/gorilla/websocket.messageWriter.Close()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:504 +0x122
  github.com/gorilla/websocket.(*messageWriter).Close()
      <autogenerated>:7 +0xd5
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Close()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:114 +0x81
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x89f
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Goroutine 40 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187

Goroutine 36 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187
==================
==================
WARNING: DATA RACE
Write by goroutine 40:
  runtime.slicecopy()
      /build/go/src/go-1.4.2/src/runtime/slice.go:94 +0x0
  github.com/gorilla/websocket.messageWriter.write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:446 +0x3f1
  github.com/gorilla/websocket.messageWriter.Write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:454 +0x7d
  github.com/gorilla/websocket.(*messageWriter).Write()
      <autogenerated>:4 +0xf9
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Write()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:108 +0x97
  github.com/googollee/go-socket%2eio.(*trimWriter).Write()
      /home/dieter/go/src/github.com/googollee/go-socket.io/trim_writer.go:40 +0x524
  encoding/json.(*Encoder).Encode()
      /build/go/src/go-1.4.2/src/encoding/json/stream.go:173 +0x27d
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x874
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Previous read by goroutine 36:
  syscall.raceReadRange()
      /build/go/src/go-1.4.2/src/syscall/race.go:25 +0x40
  syscall.Write()
      /build/go/src/go-1.4.2/src/syscall/syscall_unix.go:154 +0xb4
  net.(*netFD).Write()
      /build/go/src/go-1.4.2/src/net/fd_unix.go:327 +0x416
  net.(*conn).Write()
      /build/go/src/go-1.4.2/src/net/net.go:129 +0x124
  net.(*TCPConn).Write()
      <autogenerated>:37 +0x85
  github.com/gorilla/websocket.(*Conn).write()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:230 +0x309
  github.com/gorilla/websocket.(*Conn).flushFrame()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:384 +0x9b2
  github.com/gorilla/websocket.messageWriter.Close()
      /home/dieter/go/src/github.com/gorilla/websocket/conn.go:504 +0x122
  github.com/gorilla/websocket.(*messageWriter).Close()
      <autogenerated>:7 +0xd5
  github.com/googollee/go-engine.io/parser.(*PacketEncoder).Close()
      /home/dieter/go/src/github.com/googollee/go-engine.io/parser/packet.go:114 +0x81
  github.com/googollee/go-socket%2eio.(*encoder).encodePacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:127 +0x89f
  github.com/googollee/go-socket%2eio.(*encoder).Encode()
      /home/dieter/go/src/github.com/googollee/go-socket.io/parser.go:81 +0xdc
  github.com/googollee/go-socket%2eio.(*socket).send()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:78 +0x210
  github.com/googollee/go-socket%2eio.(*socketHandler).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:77 +0x594
  github.com/googollee/go-socket%2eio.(*socket).Emit()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:61 +0x99
  github.com/grafana/grafana/pkg/api.RefreshCollector()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:221 +0xa2f
  github.com/grafana/grafana/pkg/api.(*CollectorContext).OnConnection()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:156 +0x647
  github.com/grafana/grafana/pkg/api.func·015()
      /home/dieter/go/src/github.com/grafana/grafana/pkg/api/socketio.go:113 +0x2aa
  runtime.call16()
      /build/go/src/go-1.4.2/src/runtime/asm_amd64.s:401 +0x44
  reflect.Value.Call()
      /build/go/src/go-1.4.2/src/reflect/value.go:296 +0xd8
  github.com/googollee/go-socket%2eio.(*caller).Call()
      /home/dieter/go/src/github.com/googollee/go-socket.io/caller.go:75 +0x53c
  github.com/googollee/go-socket%2eio.(*socketHandler).onPacket()
      /home/dieter/go/src/github.com/googollee/go-socket.io/handler.go:158 +0x5cb
  github.com/googollee/go-socket%2eio.(*socket).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/socket.go:118 +0x2e5
  github.com/googollee/go-socket%2eio.func·003()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:93 +0x35

Goroutine 40 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187

Goroutine 36 (running) created at:
  github.com/googollee/go-socket%2eio.(*Server).loop()
      /home/dieter/go/src/github.com/googollee/go-socket.io/server.go:94 +0x187
==================

Periodic 'permission denied'

I consistently get periodic 'permission denied' with navigating around the current staging server.

Reloading causes it to go away, but it is definitely an annoyance.

This isn't a one-off issue as it's happening both at home on Windows/Chrome and at work on OSX/Chrome. @mattttt also said this has been happening to him periodically.

map panel

We need to create a map panel to support map functionality around Collectors, both in the Litmus pages as well as the Grafana Dashboards.

Ideally this can be accomplished as a stock Grafana panel, and can be used in an embedded manner in necessary Litmus pages.

Requirements of the map:

  • Autowindow/autozoom based on the items selected (ie. smart enough to show the world for listing all collectors, but zooming into Europe for EMEA, down to showing New York metro for someone looking at a hypothetical "NYC" tag, etc etc)
  • Be able to represent 1-5 values on each item in the map (either as a color shade, dots, etc etc), alongside annotations or notes
  • Make sure its consistent with our look and feel
  • Ideally not dependent on external accounts / costs

helper Text in Home Dashboard

When new Litmus users log in, it'd be nice to welcome them in the Home dashboard. Eventually this can link to help, chat, docs, etc, etc.

Here's some sample text welcoming a user to Litmus:

Welcome to raintank Litmus!

Litmus allows you to monitor the network quality of anything from anywhere.

Whether you have a simple blog or a globally distributed application, Litmus can help you analyze its performance and availability from around the world.

Litmus is currently in restricted alpha. Your feedback is much appreciated and helps make it better.

Setting template variables via URL parameter doesn't consistently work

Need to be able to set/override Template variables by passing URL params.

Currently trying to pass &var-endpoint=blah&var-collector=bar

Should this work? Am I running into problems with multi variable Templating?

Behavior seems really inconsistent. A lot of times the correct variable will show in the Template drop-down, but the value itself isn't selected. This causes the panels to have no data unless the endpoint is explicitly selected.

Also needs to account for multiple variables too (which can be a graphite style glob eg. "{foo,bar}"..)

endpoint modal tweaks

Some of this will change with Matts new modals, but here are some small tweaks:

  1. Change the text on the button from "New Endpoints" to "New Endpoint"

  2. When adding a new Endpoint, change the description from "Site name" to "Domain name"

  3. When adding a new Endpoint, don't show the "Summary" tab or the button to the Dashboard; neither are valid until the Endpoint is created.

IsGrafanaAdmin

I am little worried that IsGrafanaAdmin is used so much, this is a temporary flag that marks a super admin that will probably replaced with a more detailed role and permission system.

It looks like public collectors are controlled by IsGrafanaAdmin. Is there not a better way to do this? That public collectors bellow to a specific organization and the admin for that org can edit them?

I see conditionals for IsGrafanaAdmin in many places and this feels very dirty and fragile. But I am not sure, just trying to review some raintank grafana code to see if there is anything to worry about long term. This might not be a big issue, just one thing that popped into my head.

The same thing about using isGrafanaAdmin for ApiKeys seems like a big security issue. Basically all remote collectors will have a super duper password that can do everything (or am I missing something?).

    </li>
                            <li ng-hide="collector.public && !contextSrv.isGrafanaAdmin"h>
                                <a href="collectors/edit/{{collector.id}}">
                                    Edit
                                </a>
                            </li>
                            <li ng-hide="collector.public && !contextSrv.isGrafanaAdmin">
                                <a ng-click="remove(collector)">
                                    Delete
                                </a>
                            </li>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.