From 235bbc9c7ed8fa28294a23e33143a6b288d9a7ad Mon Sep 17 00:00:00 2001 From: "Haneysmith, Nathan" Date: Thu, 20 Aug 2015 11:15:36 -0700 Subject: [PATCH 001/122] custom login hints via config file --- conf/sample.ini | 3 +++ pkg/api/login.go | 1 + pkg/setting/setting.go | 2 ++ public/app/controllers/loginCtrl.js | 1 + public/app/partials/login.html | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/conf/sample.ini b/conf/sample.ini index 9a8d9aa3908..e8122766e9f 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -130,6 +130,9 @@ # Default role new users will be automatically assigned (if disabled above is set to true) ;auto_assign_org_role = Viewer +# Background text for the user field on the login page +;login_hint = email or username + #################################### Anonymous Auth ########################## [auth.anonymous] # enable anonymous access diff --git a/pkg/api/login.go b/pkg/api/login.go index 8863e1b10c1..d691270ad72 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -28,6 +28,7 @@ func LoginView(c *middleware.Context) { settings["googleAuthEnabled"] = setting.OAuthService.Google settings["githubAuthEnabled"] = setting.OAuthService.GitHub settings["disableUserSignUp"] = !setting.AllowUserSignUp + settings["loginHint"] = setting.LoginHint if !tryLoginUsingRememberCookie(c) { c.HTML(200, VIEW_INDEX) diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 3ac4b16db64..907d12479d8 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -79,6 +79,7 @@ var ( AllowUserOrgCreate bool AutoAssignOrg bool AutoAssignOrgRole string + LoginHint string // Http auth AdminUser string @@ -392,6 +393,7 @@ func NewConfigContext(args *CommandLineArgs) { AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true) AutoAssignOrg = users.Key("auto_assign_org").MustBool(true) AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Read Only Editor", "Viewer"}) + LoginHint = users.Key("login_hint").String() // anonymous access AnonymousEnabled = Cfg.Section("auth.anonymous").Key("enabled").MustBool(false) diff --git a/public/app/controllers/loginCtrl.js b/public/app/controllers/loginCtrl.js index 40e8009b399..9d27687c5ba 100644 --- a/public/app/controllers/loginCtrl.js +++ b/public/app/controllers/loginCtrl.js @@ -19,6 +19,7 @@ function (angular, config) { $scope.googleAuthEnabled = config.googleAuthEnabled; $scope.githubAuthEnabled = config.githubAuthEnabled; $scope.disableUserSignUp = config.disableUserSignUp; + $scope.loginHint = config.loginHint; $scope.loginMode = true; $scope.submitBtnText = 'Log in'; diff --git a/public/app/partials/login.html b/public/app/partials/login.html index f311c929b66..aaff2f6fd53 100644 --- a/public/app/partials/login.html +++ b/public/app/partials/login.html @@ -26,7 +26,7 @@ User
  • - +
  • From 74ea26615734776f091e42433204ddb1ff52fc69 Mon Sep 17 00:00:00 2001 From: "Haneysmith, Nathan" Date: Thu, 20 Aug 2015 11:20:40 -0700 Subject: [PATCH 002/122] add login hint to defaults.ini --- conf/defaults.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conf/defaults.ini b/conf/defaults.ini index 7ca5191c4e7..39899efb9ff 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -131,6 +131,9 @@ auto_assign_org = true # Default role new users will be automatically assigned (if auto_assign_org above is set to true) auto_assign_org_role = Viewer +# Background text for the user field on the login page +login_hint = email or username + #################################### Anonymous Auth ########################## [auth.anonymous] # enable anonymous access From 7e2f653bc7131d09b91d620caa2fed8aa30809dd Mon Sep 17 00:00:00 2001 From: Nick Christus Date: Sat, 10 Oct 2015 14:17:07 -0400 Subject: [PATCH 003/122] added alerting tab stub and styles --- public/app/features/panel/partials/panel.html | 5 + public/app/panels/graph/alerting.html | 233 ++++++++++++++++++ public/app/panels/graph/module.js | 1 + public/img/CopyQuery.png | Bin 0 -> 144 bytes public/img/critical.svg | 15 ++ public/img/envelope.png | Bin 0 -> 187 bytes public/img/online.svg | 12 + public/img/warn-tiny.svg | 16 ++ public/img/warn.svg | 22 ++ public/less/alerting.less | 42 ++++ public/less/gfbox.less | 7 + public/less/grafana.less | 1 + public/less/overrides.less | 9 + public/less/tightform.less | 6 + 14 files changed, 369 insertions(+) create mode 100644 public/app/panels/graph/alerting.html create mode 100644 public/img/CopyQuery.png create mode 100644 public/img/critical.svg create mode 100644 public/img/envelope.png create mode 100644 public/img/online.svg create mode 100644 public/img/warn-tiny.svg create mode 100644 public/img/warn.svg create mode 100644 public/less/alerting.less diff --git a/public/app/features/panel/partials/panel.html b/public/app/features/panel/partials/panel.html index a7fef0f5d67..65f482161f8 100644 --- a/public/app/features/panel/partials/panel.html +++ b/public/app/features/panel/partials/panel.html @@ -35,6 +35,11 @@ + +
    + There are unsaved changes. + +
    diff --git a/public/app/panels/graph/alerting.html b/public/app/panels/graph/alerting.html new file mode 100644 index 00000000000..7230c6ef488 --- /dev/null +++ b/public/app/panels/graph/alerting.html @@ -0,0 +1,233 @@ +
    + Last updated by Grafana October 4, 2015 12:15:04 by $username +
    +
    General Alerting Options
    +
    +
      +
    • + Alert Title +
    • +
    • + +
    • +
    • + Alerting Backend +
    • +
    • + +
    • +
    • + + + +
    • +
    +
    +
    +
    +
    +
    +
    Choose your query:
    +

    Select an exising query to alert on:

    +
    +
    +
      +
    • +
    • None
    • +
    +
    +
    +
    +
    +
    +
    +
      +
    • +
    • A
    • +
    • apps
    • +
    • +
    • fakesite
    • +
    • counters
    • +
    • requests
    • +
    • count
    • +
    • scaleToSeconds(1)
    • +
    • aliasByNode(2)
    • +
    • +
    +
    +
    +
    +
    +
    +
      +
    • +
    • B
    • +
    • Metric: us-west-2 AWS/EC2 CPUUtilization Stats: Minimum Maximum Dimensions InstanceIS = i-b0e8a447 Alias {{stat}} Period 60
    • +
    • +
    +
    +
    +
    +
    +
    +
      +
    • +
    • C
    • +
    • Query: avg(counters_logins) by(server) Legend Format: {{app}} - {{server}} Step: 1s Resolution: 1/2
    • +
    • +
    +
    +
    +
    +
    +
    +
      +
    • +
    • D
    • +
    • SELECT mean(value) FROM logins.count WHERE hostname = /$Hostname$/ GROUP BY time($internal) hostname
    • +
    • +
    +
    +
    +
    +
    +
    +
      +
    • +
    • E
    • +
    • Metric: apps.backend.backend_01.counters.requests.count Alias: Bristow Aggregator: Sum Downsample: 1m Aggregator Sum Tags host = test
    • +
    • +
    +
    +
    +
    +
    +
    +

    Or write a new custom alerting query:

    +
    +
    +
      +
    • +
    • + + + +
    • +
    • + select metric +
    • +
    • + +
    • +
    +
    +
    +
    +
    +
    +
    +
    Define Your States
    +
    +
      +
    • + by +
    • +
    • + +
    • +
    • + the values in the query over the last +
    • +
    • + +
    • +
    +
    +
    +
    +
    +
    +
    +
    +
      +
    • + Warn +
    • +
    • + +
    • +
    • + +
    • +
    • + .notify +
    • +
    • + +
    • +
    • + + + +
    • +
    +
    +
    +
    +
      +
    • + Critical +
    • +
    • + +
    • +
    • + +
    • +
    • + .notify +
    • +
    • + +
    • +
    • + + + +
    • +
    +
    +
    +
    +
    +
    +
    +
    What to Say Variables | Preview
    +
    +
      +
    • + Summary +
    • +
    • + +
    • +
    +
    +
    +
    +
      +
    • + Description +
    • +
    • + +
    • +
    +
    +
    +
    +
    diff --git a/public/app/panels/graph/module.js b/public/app/panels/graph/module.js index 5cdeab799de..a1e56f8c5eb 100644 --- a/public/app/panels/graph/module.js +++ b/public/app/panels/graph/module.js @@ -34,6 +34,7 @@ function (angular, $, _, kbn, moment, TimeSeries, PanelMeta) { $scope.panelMeta.addEditorTab('Axes & Grid', 'app/panels/graph/axisEditor.html'); $scope.panelMeta.addEditorTab('Display Styles', 'app/panels/graph/styleEditor.html'); $scope.panelMeta.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html'); + $scope.panelMeta.addEditorTab('Alerting', 'app/panels/graph/alerting.html'); $scope.panelMeta.addExtendedMenuItem('Export CSV', '', 'exportCsv()'); $scope.panelMeta.addExtendedMenuItem('Toggle legend', '', 'toggleLegend()'); diff --git a/public/img/CopyQuery.png b/public/img/CopyQuery.png new file mode 100644 index 0000000000000000000000000000000000000000..b9829c23b2ff6146760e6c5f5264a713aceb7e99 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!2%?E=C*AFQsJI1jv*C{$u>XU+bc6mCH%=h z&$5jFPx*lfES-Y-l^f + + + + + + + diff --git a/public/img/envelope.png b/public/img/envelope.png new file mode 100644 index 0000000000000000000000000000000000000000..59ef8a38aba65a69c72ab8a97b1f3421e35d8cac GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh0wlLOK8*rWO`a}}Ar*{sFC1NX$Uvsyqkh?Y zwi2b3NhwY2ITLh(Vprr`DCRAH{+*PM@abWfebchTzZ`Iu^9tMWYgE%|E;Ht-+X6|`CL7_(nktyYo+`**QehTO=4 lFAt}D-Cvh6m;2rg2C+2#McIiyOhDH#c)I$ztaD0e0s!QaM^gX* literal 0 HcmV?d00001 diff --git a/public/img/online.svg b/public/img/online.svg new file mode 100644 index 00000000000..279fbec3a90 --- /dev/null +++ b/public/img/online.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/public/img/warn-tiny.svg b/public/img/warn-tiny.svg new file mode 100644 index 00000000000..e8e91f4452c --- /dev/null +++ b/public/img/warn-tiny.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/public/img/warn.svg b/public/img/warn.svg new file mode 100644 index 00000000000..8caee82c3f5 --- /dev/null +++ b/public/img/warn.svg @@ -0,0 +1,22 @@ + + + + + + + diff --git a/public/less/alerting.less b/public/less/alerting.less new file mode 100644 index 00000000000..9054584e23e --- /dev/null +++ b/public/less/alerting.less @@ -0,0 +1,42 @@ +.copy-query { + display: block; + width: 30px; + height: 36px; + margin: 0; + padding: 0; + border: 0; + background: transparent url(/img/CopyQuery.png) 50% 50% no-repeat; + cursor: pointer; +} + +.alert-state { + display: inline-block; + padding-left: 30px; + background: 0 50% no-repeat; + background-size: 20px auto; +} + +.alert-state-online { + background-image: url('/img/online.svg'); +} + +.alert-state-warning { + background-image: url('/img/warn-tiny.svg'); +} + +.alert-state-critical { + background-image: url('/img/critical.svg'); +} + +.alert-notify-emails { + width: 400px; + border-right: 1px solid @black; +} + +.alert-notify-emails .bootstrap-tagsinput { + width: 394px; // offset for 8px left padding and border width +} + +.alert-notify-emails .bootstrap-tagsinput input { + border: 0; +} diff --git a/public/less/gfbox.less b/public/less/gfbox.less index eb386f740d7..48d0b6a7ca8 100644 --- a/public/less/gfbox.less +++ b/public/less/gfbox.less @@ -25,6 +25,13 @@ } } +.gf-box-header-save-btn { + padding: 7px 0; + float: right; + color: @grayLight; + font-style: italic; +} + .gf-box-body { padding: 20px; min-height: 150px; diff --git a/public/less/grafana.less b/public/less/grafana.less index 6e23faa214d..0d4e5f44dc0 100644 --- a/public/less/grafana.less +++ b/public/less/grafana.less @@ -18,6 +18,7 @@ @import "fonts.less"; @import "tabs.less"; @import "timepicker.less"; +@import "alerting.less"; .row-control-inner { padding:0px; diff --git a/public/less/overrides.less b/public/less/overrides.less index fb6544cd99c..229627c0896 100644 --- a/public/less/overrides.less +++ b/public/less/overrides.less @@ -560,6 +560,15 @@ div.flot-text { background-color: darken(@purple, 10%); } +.label-tag-email { + padding-left: 25px; + background: @black url(/img/envelope.png) 5px 50% no-repeat !important; + border-color: @black !important; + font-size: 12px; + font-weight: normal; + border-radius: 5px; +} + // inspector .inspector-request-table { diff --git a/public/less/tightform.less b/public/less/tightform.less index 494497653ed..f65a991613a 100644 --- a/public/less/tightform.less +++ b/public/less/tightform.less @@ -156,6 +156,12 @@ input[type=checkbox].tight-form-checkbox { margin: 0; } +.tight-form-textarea { + height: 200px; + margin: 0; + box-sizing: border-box; +} + select.tight-form-input { border: none; border-right: 1px solid @grafanaTargetSegmentBorder; From 23404decead89577dad4b23471aa1bf6645dc263 Mon Sep 17 00:00:00 2001 From: Nick Christus Date: Sun, 11 Oct 2015 16:59:40 -0400 Subject: [PATCH 004/122] added global alerts list stub and styles --- public/app/core/routes/all.js | 3 + .../dashboard/partials/globalAlerts.html | 282 ++++++++++++++++++ public/app/panels/graph/alerting.html | 119 ++++---- public/less/filter-list.less | 167 +++++++++++ public/less/gfbox.less | 4 + public/less/grafana.less | 1 + public/less/variables.dark.less | 6 + public/less/variables.light.less | 6 + 8 files changed, 522 insertions(+), 66 deletions(-) create mode 100644 public/app/features/dashboard/partials/globalAlerts.html create mode 100644 public/less/filter-list.less diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index a7e36a0e228..7a912621ba5 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -131,6 +131,9 @@ define([ templateUrl: 'app/partials/reset_password.html', controller : 'ResetPasswordCtrl', }) + .when('/global-alerts', { + templateUrl: 'app/features/dashboard/partials/globalAlerts.html', + }) .otherwise({ templateUrl: 'app/partials/error.html', controller: 'ErrorCtrl' diff --git a/public/app/features/dashboard/partials/globalAlerts.html b/public/app/features/dashboard/partials/globalAlerts.html new file mode 100644 index 00000000000..d66c7e98d8c --- /dev/null +++ b/public/app/features/dashboard/partials/globalAlerts.html @@ -0,0 +1,282 @@ + + + + +
    +
    +

    Global alerts

    + +
    +
    +
      +
    • Filters:
    • +
    • Alert State
    • +
    • +
    • Dashboards
    • +
    • +
    • + + + +
    • +
    +
    +
    +
    +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + 2 selected, showing 6 of 6 total +
    • +
    +
      +
    • + +
      +
      Alert query configure alerting
      +
      +
        +
      • A
      • +
      • apps
      • +
      • +
      • fakesite
      • +
      • counters
      • +
      • requests
      • +
      • count
      • +
      • scaleToSeconds(1)
      • +
      • aliasByNode(2)
      • +
      +
      +
      +
      +
    • +
    • + +
      +
      Alert query configure alerting
      +
      +
        +
      • A
      • +
      • apps
      • +
      • +
      • fakesite
      • +
      • counters
      • +
      • requests
      • +
      • count
      • +
      • scaleToSeconds(1)
      • +
      • aliasByNode(2)
      • +
      +
      +
      +
      +
    • +
    • + +
      +
      Alert query configure alerting
      +
      +
        +
      • A
      • +
      • apps
      • +
      • +
      • fakesite
      • +
      • counters
      • +
      • requests
      • +
      • count
      • +
      • scaleToSeconds(1)
      • +
      • aliasByNode(2)
      • +
      +
      +
      +
      +
    • +
    • + +
      +
      Alert query configure alerting
      +
      +
        +
      • A
      • +
      • apps
      • +
      • +
      • fakesite
      • +
      • counters
      • +
      • requests
      • +
      • count
      • +
      • scaleToSeconds(1)
      • +
      • aliasByNode(2)
      • +
      +
      +
      +
      +
    • +
    • + +
      +
      Alert query configure alerting
      +
      +
        +
      • A
      • +
      • apps
      • +
      • +
      • fakesite
      • +
      • counters
      • +
      • requests
      • +
      • count
      • +
      • scaleToSeconds(1)
      • +
      • aliasByNode(2)
      • +
      +
      +
      +
      +
    • +
    +
    +
    diff --git a/public/app/panels/graph/alerting.html b/public/app/panels/graph/alerting.html index 7230c6ef488..9e08fc4f6cb 100644 --- a/public/app/panels/graph/alerting.html +++ b/public/app/panels/graph/alerting.html @@ -31,77 +31,64 @@
    Choose your query:

    Select an exising query to alert on:

    -
    -
    -
      -
    • -
    • None
    • -
    -
    -
    +
    +
      +
    • +
    • None
    • +
    +
    -
    -
    -
    -
      -
    • -
    • A
    • -
    • apps
    • -
    • -
    • fakesite
    • -
    • counters
    • -
    • requests
    • -
    • count
    • -
    • scaleToSeconds(1)
    • -
    • aliasByNode(2)
    • -
    • -
    -
    -
    +
    +
      +
    • +
    • A
    • +
    • apps
    • +
    • +
    • fakesite
    • +
    • counters
    • +
    • requests
    • +
    • count
    • +
    • scaleToSeconds(1)
    • +
    • aliasByNode(2)
    • +
    • +
    +
    -
    -
    -
      -
    • -
    • B
    • -
    • Metric: us-west-2 AWS/EC2 CPUUtilization Stats: Minimum Maximum Dimensions InstanceIS = i-b0e8a447 Alias {{stat}} Period 60
    • -
    • -
    -
    -
    +
    +
      +
    • +
    • B
    • +
    • Metric: us-west-2 AWS/EC2 CPUUtilization Stats: Minimum Maximum Dimensions InstanceIS = i-b0e8a447 Alias {{stat}} Period 60
    • +
    • +
    +
    -
    -
    -
      -
    • -
    • C
    • -
    • Query: avg(counters_logins) by(server) Legend Format: {{app}} - {{server}} Step: 1s Resolution: 1/2
    • -
    • -
    -
    -
    +
    +
      +
    • +
    • C
    • +
    • Query: avg(counters_logins) by(server) Legend Format: {{app}} - {{server}} Step: 1s Resolution: 1/2
    • +
    • +
    +
    -
    -
    -
      -
    • -
    • D
    • -
    • SELECT mean(value) FROM logins.count WHERE hostname = /$Hostname$/ GROUP BY time($internal) hostname
    • -
    • -
    -
    -
    +
    +
      +
    • +
    • D
    • +
    • SELECT mean(value) FROM logins.count WHERE hostname = /$Hostname$/ GROUP BY time($internal) hostname
    • +
    • +
    +
    -
    -
    -
      -
    • -
    • E
    • -
    • Metric: apps.backend.backend_01.counters.requests.count Alias: Bristow Aggregator: Sum Downsample: 1m Aggregator Sum Tags host = test
    • -
    • -
    -
    -
    +
    +
      +
    • +
    • E
    • +
    • Metric: apps.backend.backend_01.counters.requests.count Alias: Bristow Aggregator: Sum Downsample: 1m Aggregator Sum Tags host = test
    • +
    • +
    +
    diff --git a/public/less/filter-list.less b/public/less/filter-list.less new file mode 100644 index 00000000000..50da5864db0 --- /dev/null +++ b/public/less/filter-list.less @@ -0,0 +1,167 @@ +// ========================================================================== +// FILTER LIST +// ========================================================================== + + + +// List +// -------------------------------------------------------------------------- + +.filter-list { + max-width: 1000px; + margin: 0; + padding: 0; + list-style: none; +} + +.filter-list > li { + padding: 10px; + margin-bottom: 2px; + background: @grafanaPanelBackground; + + &:last-child { + margin: 0; + } +} + + + +// Card +// -------------------------------------------------------------------------- + +.filter-list-card { + display: table; + width: 100%; + margin: 0; + padding: 0; + list-style: none; +} + +.filter-list-card > li { + display: table-cell; + vertical-align: top; +} + +.filter-list-card-select { + width: 23px; + padding-right: 5px; +} + +.filter-list-card-title { + display: block; + font-size: 16px; + font-weight: normal; +} + +.filter-list-card-status { + color: #777; + font-size: 12px; +} + +.filter-list-card-state { + display: inline-block; + padding: 5px 0 0 28px; + background: 0 bottom no-repeat; + background-size: 24px auto; + font-size: 14px; + text-transform: uppercase; + + &.online { + background-image: url('/img/online.svg'); + color: @online; + } + + &.warn { + background-image: url('/img/warn-tiny.svg'); + color: @warn; + } + + &.critical { + background-image: url('/img/critical.svg'); + color: @critical; + } +} + +.filter-list-card-controls { + float: right; +} + +.filter-list-card-links, +.filter-list-card-config, +.filter-list-card-expand { + display: inline-block; + vertical-align: middle; +} + +.filter-list-card-link { + display: block; + color: #777; + text-align: right; + + > a { + color: #777; + } +} + +.filter-list-card-config { + padding: 8px 8px 8px 16px; + color: #777; + font-size: 25px; + + > a { + color: #777; + } +} + +.filter-list-card-expand { + width: 20px; + padding: 8px 0 8px 8px; + color: #aaa; + font-size: 30px; + text-align: center; + cursor: pointer; +} + +.filter-list-card-details { + padding: 20px 0 0 30px; +} + +.filter-list-card-details-heading { + font-weight: normal; + + > a { + float: right; + color: @blue; + font-size: 12px; + } +} + + + +// Filters +// -------------------------------------------------------------------------- + +.filter-list-filters { + display: inline-block; + margin-bottom: 40px; +} + + + +// Actions +// -------------------------------------------------------------------------- + +.filter-list-actions { + margin: 0 0 10px; + padding: 0; + list-style: none; +} + +.filter-list-actions > li { + display: inline-block; + margin-right: 10px; +} + +.filter-list-actions-selected { + text-transform: uppercase; +} diff --git a/public/less/gfbox.less b/public/less/gfbox.less index 48d0b6a7ca8..d173ace1787 100644 --- a/public/less/gfbox.less +++ b/public/less/gfbox.less @@ -80,6 +80,10 @@ max-width: 653px; } +.page-wide { + max-width: none; +} + .admin-page { max-width: 800px; margin-left: 10px; diff --git a/public/less/grafana.less b/public/less/grafana.less index 0d4e5f44dc0..aa58f749b82 100644 --- a/public/less/grafana.less +++ b/public/less/grafana.less @@ -19,6 +19,7 @@ @import "tabs.less"; @import "timepicker.less"; @import "alerting.less"; +@import "filter-list.less"; .row-control-inner { padding:0px; diff --git a/public/less/variables.dark.less b/public/less/variables.dark.less index 3324c3f4b86..af8f3cdec75 100644 --- a/public/less/variables.dark.less +++ b/public/less/variables.dark.less @@ -25,6 +25,12 @@ @purple: #9933CC; @variable: #32D1DF; +// Status colors +// ------------------------- +@online: #10a345; +@warn: #ffc03c; +@critical: #ed2e18; + // grafana Variables // ------------------------- @grafanaPanelBackground: @grayDarker; diff --git a/public/less/variables.light.less b/public/less/variables.light.less index 27dcf8575f4..67a8dfd7257 100644 --- a/public/less/variables.light.less +++ b/public/less/variables.light.less @@ -31,6 +31,12 @@ @purple: #9954BB; @variable: #2AB2E4; +// Status colors +// ------------------------- +@online: #10a345; +@warn: #ffc03c; +@critical: #ed2e18; + // grafana Variables // ------------------------- @grafanaPanelBackground: @grayLighter; From aa9093bcf6693d884a0ff332f04de27d8f66459c Mon Sep 17 00:00:00 2001 From: Nick Christus Date: Tue, 27 Oct 2015 23:26:11 -0500 Subject: [PATCH 005/122] updated-list-views: added filter-table less component, updating styles for data sources table --- .../features/org/partials/datasources.html | 76 ++++++++++--------- public/less/filter-table.less | 48 ++++++++++++ public/less/grafana.less | 1 + 3 files changed, 90 insertions(+), 35 deletions(-) create mode 100644 public/less/filter-table.less diff --git a/public/app/features/org/partials/datasources.html b/public/app/features/org/partials/datasources.html index a2e62673e70..b1b37a572a9 100644 --- a/public/app/features/org/partials/datasources.html +++ b/public/app/features/org/partials/datasources.html @@ -5,47 +5,53 @@ -
    -
    +
    +

    Data sources

    No datasources defined
    - - - - - - - - - - - - - - - +
    NameUrl
    -   - {{ds.name}} - - {{ds.url}} - - - default - - - - - Edit - - - - - -
    + + + + + + + + + + + + + + + + + +
    NameUrl
    + +   + {{ds.name}} + + + {{ds.url}} + + + default + + + + + Edit + + + + + +
    diff --git a/public/less/filter-table.less b/public/less/filter-table.less new file mode 100644 index 00000000000..7b9f7a47b10 --- /dev/null +++ b/public/less/filter-table.less @@ -0,0 +1,48 @@ +// ========================================================================== +// FILTER TABLE +// ========================================================================== + + + +// Table +// -------------------------------------------------------------------------- + +.filter-table * { + box-sizing: border-box; +} + +.filter-table { + width: 100%; + table-layout: fixed; + border-collapse: collapse; +} + +.filter-table tr { + background: @grafanaPanelBackground; + border-bottom: 2px solid @bodyBackground; +} + +.filter-table th { + padding: 10px 15px 10px 0; + text-align: left; + + &:first-child { + padding-left: 15px; + } +} + +.filter-table td { + padding: 15px 15px 15px 0; + + &:first-child { + padding-left: 15px; + } +} + +.filter-table .ellipsis { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/public/less/grafana.less b/public/less/grafana.less index aa58f749b82..3ee21297dd0 100644 --- a/public/less/grafana.less +++ b/public/less/grafana.less @@ -20,6 +20,7 @@ @import "timepicker.less"; @import "alerting.less"; @import "filter-list.less"; +@import "filter-table.less"; .row-control-inner { padding:0px; From e63ff167a79a2365a6e43ff93c6594497ea2b7d2 Mon Sep 17 00:00:00 2001 From: Nick Christus Date: Thu, 29 Oct 2015 21:09:21 -0500 Subject: [PATCH 006/122] updated-list-views: added filter controls, updated tables on API Keys and Data Sources --- .../dashboard/partials/globalAlerts.html | 6 +- .../features/org/partials/datasources.html | 56 +++++++++++- .../app/features/org/partials/orgApiKeys.html | 87 +++++++++++++++---- public/less/filter-controls.less | 33 +++++++ public/less/filter-list.less | 31 ------- public/less/gfbox.less | 2 +- public/less/grafana.less | 1 + 7 files changed, 161 insertions(+), 55 deletions(-) create mode 100644 public/less/filter-controls.less diff --git a/public/app/features/dashboard/partials/globalAlerts.html b/public/app/features/dashboard/partials/globalAlerts.html index d66c7e98d8c..a849f50ffdd 100644 --- a/public/app/features/dashboard/partials/globalAlerts.html +++ b/public/app/features/dashboard/partials/globalAlerts.html @@ -8,7 +8,7 @@

    Global alerts

    -
    +
    • Filters:
    • @@ -25,7 +25,7 @@
    -
      +
      • - 2 selected, showing 6 of 6 total + 2 selected, showing 6 of 6 total
        diff --git a/public/app/features/org/partials/datasources.html b/public/app/features/org/partials/datasources.html index b1b37a572a9..6cf40deccde 100644 --- a/public/app/features/org/partials/datasources.html +++ b/public/app/features/org/partials/datasources.html @@ -9,6 +9,51 @@

        Data sources

        +
        +
        +
          +
        • Filters:
        • +
        • Name
        • +
        • +
        • URL
        • +
        • +
        • + + + +
        • +
        +
        +
        +
        + +
          +
        • + +
        • +
        • + +
        • +
        • + 0 selected, showing 2 of 2 total +
        • +
        +
        No datasources defined
        @@ -16,15 +61,20 @@ - - + + + - + + - - + + @@ -76,10 +76,7 @@
        NameUrlNameUrl
        + + +   diff --git a/public/app/features/org/partials/orgApiKeys.html b/public/app/features/org/partials/orgApiKeys.html index 9db700ab437..c24b5c53ec1 100644 --- a/public/app/features/org/partials/orgApiKeys.html +++ b/public/app/features/org/partials/orgApiKeys.html @@ -4,9 +4,8 @@ -
        +
        -

        API Keys

        @@ -32,21 +31,75 @@ - - - - - - - - - - - +
        +
        +
          +
        • Filters:
        • +
        • Name
        • +
        • +
        • Role
        • +
        • +
        • + + + +
        • +
        +
        +
        +
        + +
          +
        • + +
        • +
        • + +
        • +
        • + 0 selected, showing 2 of 2 total +
        • +
        + +
        NameRole
        {{t.name}}{{t.role}} - - - -
        + + + + + + + + + + + + + + + +
        NameRole
        + + + {{t.name}}{{t.role}} + + + +
        diff --git a/public/less/filter-controls.less b/public/less/filter-controls.less new file mode 100644 index 00000000000..f1489431a7d --- /dev/null +++ b/public/less/filter-controls.less @@ -0,0 +1,33 @@ +// ========================================================================== +// FILTER CONTROLS +// ========================================================================== + + + +// Filters +// -------------------------------------------------------------------------- + +.filter-controls-filters { + display: inline-block; + margin-bottom: 40px; +} + + + +// Actions +// -------------------------------------------------------------------------- + +.filter-controls-actions { + margin: 0 0 10px; + padding: 0; + list-style: none; +} + +.filter-controls-actions > li { + display: inline-block; + margin-right: 10px; +} + +.filter-controls-actions-selected { + text-transform: uppercase; +} diff --git a/public/less/filter-list.less b/public/less/filter-list.less index 50da5864db0..181aedf4d3c 100644 --- a/public/less/filter-list.less +++ b/public/less/filter-list.less @@ -8,7 +8,6 @@ // -------------------------------------------------------------------------- .filter-list { - max-width: 1000px; margin: 0; padding: 0; list-style: none; @@ -135,33 +134,3 @@ font-size: 12px; } } - - - -// Filters -// -------------------------------------------------------------------------- - -.filter-list-filters { - display: inline-block; - margin-bottom: 40px; -} - - - -// Actions -// -------------------------------------------------------------------------- - -.filter-list-actions { - margin: 0 0 10px; - padding: 0; - list-style: none; -} - -.filter-list-actions > li { - display: inline-block; - margin-right: 10px; -} - -.filter-list-actions-selected { - text-transform: uppercase; -} diff --git a/public/less/gfbox.less b/public/less/gfbox.less index d173ace1787..46967d143c5 100644 --- a/public/less/gfbox.less +++ b/public/less/gfbox.less @@ -81,7 +81,7 @@ } .page-wide { - max-width: none; + max-width: 1000px; } .admin-page { diff --git a/public/less/grafana.less b/public/less/grafana.less index 3ee21297dd0..268b516f397 100644 --- a/public/less/grafana.less +++ b/public/less/grafana.less @@ -19,6 +19,7 @@ @import "tabs.less"; @import "timepicker.less"; @import "alerting.less"; +@import "filter-controls.less"; @import "filter-list.less"; @import "filter-table.less"; From 58dc282ca0fb4240ef67023bb948ccc7a3d8f8e5 Mon Sep 17 00:00:00 2001 From: Nick Christus Date: Tue, 3 Nov 2015 08:24:10 -0600 Subject: [PATCH 007/122] updated-list-views: updating table layout for org users --- .../features/org/partials/datasources.html | 9 +-- .../app/features/org/partials/orgUsers.html | 68 ++++++++++++++++--- public/less/filter-controls.less | 4 ++ public/less/filter-table.less | 3 +- 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/public/app/features/org/partials/datasources.html b/public/app/features/org/partials/datasources.html index 6cf40deccde..3897b3ecd3d 100644 --- a/public/app/features/org/partials/datasources.html +++ b/public/app/features/org/partials/datasources.html @@ -62,8 +62,8 @@
        NameUrlNameUrl - -   - {{ds.name}} - +   {{ds.name}} {{ds.url}} diff --git a/public/app/features/org/partials/orgUsers.html b/public/app/features/org/partials/orgUsers.html index 355131c2dbb..3cb560bd560 100644 --- a/public/app/features/org/partials/orgUsers.html +++ b/public/app/features/org/partials/orgUsers.html @@ -4,7 +4,7 @@ -
        +

        Organization users

        @@ -18,21 +18,69 @@ - - - - - - - + +
        +
        +
          +
        • Filters:
        • +
        • Login
        • +
        • +
        • Role
        • +
        • +
        • + + + +
        • +
        +
        +
        +
        + +
          +
        • + +
        • +
        • + +
        • +
        • + 0 selected, showing 1 of 1 total +
        • +
        + +
        LoginEmailRole
        + + + + + + + + - + - -
        LoginEmailRole
        {{user.login}}{{user.email}}{{user.email}} + diff --git a/public/less/filter-controls.less b/public/less/filter-controls.less index f1489431a7d..287bebe3757 100644 --- a/public/less/filter-controls.less +++ b/public/less/filter-controls.less @@ -12,6 +12,10 @@ margin-bottom: 40px; } +.tab-pane > .filter-controls-filters { + margin-top: 20px; +} + // Actions diff --git a/public/less/filter-table.less b/public/less/filter-table.less index 7b9f7a47b10..765fab5662f 100644 --- a/public/less/filter-table.less +++ b/public/less/filter-table.less @@ -13,7 +13,7 @@ .filter-table { width: 100%; - table-layout: fixed; + // table-layout: fixed; border-collapse: collapse; } @@ -23,6 +23,7 @@ } .filter-table th { + width: auto; padding: 10px 15px 10px 0; text-align: left; From 0bff097afbf7aaea31974084bfd6bffe519ecb4e Mon Sep 17 00:00:00 2001 From: Nick Owens Date: Sat, 7 Nov 2015 17:38:27 -0800 Subject: [PATCH 008/122] pkg/log: implement syslog logger --- pkg/log/syslog.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 pkg/log/syslog.go diff --git a/pkg/log/syslog.go b/pkg/log/syslog.go new file mode 100644 index 00000000000..4fe9d6a7522 --- /dev/null +++ b/pkg/log/syslog.go @@ -0,0 +1,93 @@ +package log + +import ( + "encoding/json" + "errors" + "log/syslog" +) + +type SyslogWriter struct { + syslog *syslog.Writer + Network string `json:"network"` + Address string `json:"address"` + Facility string `json:"facility"` + Tag string `json:"tag"` +} + +func NewSyslog() LoggerInterface { + return new(SyslogWriter) +} + +func (sw *SyslogWriter) Init(config string) error { + if err := json.Unmarshal([]byte(config), sw); err != nil { + return err + } + + prio, err := parseFacility(sw.Facility) + if err != nil { + return err + } + + w, err := syslog.Dial(sw.Network, sw.Address, prio, sw.Tag) + if err != nil { + return err + } + + sw.syslog = w + return nil +} + +func (sw *SyslogWriter) WriteMsg(msg string, skip, level int) error { + var err error + + switch level { + case TRACE, DEBUG: + err = sw.syslog.Debug(msg) + case INFO: + err = sw.syslog.Info(msg) + case WARN: + err = sw.syslog.Warning(msg) + case ERROR: + err = sw.syslog.Err(msg) + case CRITICAL: + err = sw.syslog.Crit(msg) + case FATAL: + err = sw.syslog.Alert(msg) + default: + err = errors.New("invalid syslog level") + } + + return err +} + +func (sw *SyslogWriter) Destroy() { + sw.syslog.Close() +} + +func (sw *SyslogWriter) Flush() {} + +var facilities = map[string]syslog.Priority{ + "user": syslog.LOG_USER, + "daemon": syslog.LOG_DAEMON, + "local0": syslog.LOG_LOCAL0, + "local1": syslog.LOG_LOCAL1, + "local2": syslog.LOG_LOCAL2, + "local3": syslog.LOG_LOCAL3, + "local4": syslog.LOG_LOCAL4, + "local5": syslog.LOG_LOCAL5, + "local6": syslog.LOG_LOCAL6, + "local7": syslog.LOG_LOCAL7, +} + +func parseFacility(facility string) (syslog.Priority, error) { + prio, ok := facilities[facility] + if !ok { + return syslog.LOG_LOCAL0, errors.New("invalid syslog facility") + } + + return prio, nil +} + +func init() { + Register("syslog", NewSyslog) +} From 20b553461b176ae395685e524e154425cfdab21e Mon Sep 17 00:00:00 2001 From: Nick Owens Date: Sat, 7 Nov 2015 18:06:31 -0800 Subject: [PATCH 009/122] conf: add syslog logging defaults --- conf/defaults.ini | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/conf/defaults.ini b/conf/defaults.ini index 69d045dc4ae..e90b99e30d3 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -245,6 +245,18 @@ daily_rotate = true # Expired days of log file(delete after max days), default is 7 max_days = 7 +[log.syslog] +level = +# Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used. +network = +address = + +# Syslog facility. user, daemon and local0 through local7 are valid. +facility = + +# Syslog tag. By default, the process' argv[0] is used. +tag = + #################################### AMPQ Event Publisher ########################## [event_publisher] enabled = false From 60e797ccc421d5aab425369311b0cb0accbabc5a Mon Sep 17 00:00:00 2001 From: Nick Owens Date: Sat, 7 Nov 2015 18:06:53 -0800 Subject: [PATCH 010/122] pkg/setting: integrate syslog logger settings --- pkg/setting/setting.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index d6a853a9cdc..291454f6134 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -567,6 +567,14 @@ func initLogging(args *CommandLineArgs) { "driver": sec.Key("driver").String(), "conn": sec.Key("conn").String(), } + case "syslog": + LogConfigs[i] = util.DynMap{ + "level": level, + "network": sec.Key("network").MustString(""), + "address": sec.Key("address").MustString(""), + "facility": sec.Key("facility").MustString("local7"), + "tag": sec.Key("tag").MustString(""), + } } cfgJsonBytes, _ := json.Marshal(LogConfigs[i]) From ef4bec1c6d870a38dd2f47b4543be8b6fef7715b Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Tue, 10 Nov 2015 19:25:59 +0900 Subject: [PATCH 011/122] fix CloudWatch dimension value suggestion --- .../datasource/cloudwatch/datasource.js | 23 ++++++++++++------- .../datasource/cloudwatch/query_ctrl.js | 19 +++++++++++++-- .../cloudwatch/specs/datasource_specs.ts | 2 +- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index eef2d77f5e2..d4c622eac55 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -124,13 +124,7 @@ function (angular, _) { }; return this.awsRequest(request).then(function(result) { - return _.chain(result.Metrics).map(function(metric) { - return _.pluck(metric.Dimensions, 'Value'); - }).flatten().uniq().sortBy(function(name) { - return name; - }).map(function(value) { - return {value: value, text: value}; - }).value(); + return _.pluck(result.Metrics, 'Dimensions'); }); }; @@ -191,7 +185,20 @@ function (angular, _) { }); } - return this.getDimensionValues(region, namespace, metricName, dimensions); + return this.getDimensionValues(region, namespace, metricName, dimensions).then(function(result) { + return _.map(result, function(dimensions) { + var values = _.chain(dimensions) + .sortBy(function(dimension) { + return dimension.Name; + }) + .map(function(dimension) { + return dimension.Name + '=' + dimension.Value; + }) + .value().join(','); + + return { text: values }; + }); + }); } var ebsVolumeIdsQuery = query.match(/^ebs_volume_ids\(([^,]+?),\s?([^,]+?)\)/); diff --git a/public/app/plugins/datasource/cloudwatch/query_ctrl.js b/public/app/plugins/datasource/cloudwatch/query_ctrl.js index 3869a5ec715..7bcc73b4323 100644 --- a/public/app/plugins/datasource/cloudwatch/query_ctrl.js +++ b/public/app/plugins/datasource/cloudwatch/query_ctrl.js @@ -76,7 +76,7 @@ function (angular, _) { } }; - $scope.getDimSegments = function(segment) { + $scope.getDimSegments = function(segment, $index) { if (segment.type === 'operator') { return $q.when([]); } var target = $scope.target; @@ -88,7 +88,22 @@ function (angular, _) { query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, {}); } - return query.then($scope.transformToSegments(true)).then(function(results) { + return query.then(function(results) { + if (segment.type === 'value') { + results = _.chain(results) + .flatten(true) + .filter(function(dimension) { + return dimension.Name === templateSrv.replace($scope.dimSegments[$index-2].value); + }) + .pluck('Value') + .uniq() + .map(function(value) { + return {value: value, text: value}; + }) + .value(); + } + return $scope.transformToSegments(true)(results); + }).then(function(results) { if (segment.type === 'key') { results.splice(0, 0, angular.copy($scope.removeDimSegment)); } diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts index 4714a642d30..a6d4330a37e 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts @@ -165,7 +165,7 @@ describe('CloudWatchDatasource', function() { }); it('should call __ListMetrics and return result', () => { - expect(scenario.result[0].text).to.be('i-12345678'); + expect(scenario.result[0].text).to.be('InstanceId=i-12345678'); expect(scenario.request.data.action).to.be('ListMetrics'); }); }); From add5bb47d5a84a620abfe599e04c749b1901c1de Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Sat, 14 Nov 2015 19:54:24 +0900 Subject: [PATCH 012/122] add dimensions() to CloudWatch templating query --- .../datasource/cloudwatch/datasource.js | 64 ++++++++++++++----- .../datasource/cloudwatch/query_ctrl.js | 20 +----- .../cloudwatch/specs/datasource_specs.ts | 26 +++++++- 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index d4c622eac55..4512aed972b 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -112,14 +112,14 @@ function (angular, _) { }); }; - CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensions) { + CloudWatchDatasource.prototype.getDimensions = function(region, namespace, metricName, filterDimensions) { var request = { region: templateSrv.replace(region), action: 'ListMetrics', parameters: { namespace: templateSrv.replace(namespace), metricName: templateSrv.replace(metricName), - dimensions: convertDimensionFormat(dimensions, {}), + dimensions: convertDimensionFormat(filterDimensions, {}), } }; @@ -128,6 +128,17 @@ function (angular, _) { }); }; + CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) { + return this.getDimensions(region, namespace, metricName, filterDimensions).then(function(dimensions) { + return _.chain(dimensions) + .flatten() + .filter(function(dimension) { + return dimension.Name === dimensionKey; + }) + .pluck('Value').uniq().sortBy().value(); + }); + }; + CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) { return this.awsRequest({ region: region, @@ -140,6 +151,8 @@ function (angular, _) { var region; var namespace; var metricName; + var dimensionPart; + var dimensions; var transformSuggestData = function(suggestData) { return _.map(suggestData, function(v) { @@ -147,6 +160,21 @@ function (angular, _) { }); }; + var parseDimensions = function(dimensionPart) { + if (_.isEmpty(dimensionPart)) { + return {}; + } + var dimensions = {}; + _.each(dimensionPart.split(','), function(v) { + var t = v.split('='); + if (t.length !== 2) { + throw new Error('Invalid query format'); + } + dimensions[t[0]] = t[1]; + }); + return dimensions; + }; + var regionQuery = query.match(/^regions\(\)/); if (regionQuery) { return this.getRegions(); @@ -167,25 +195,31 @@ function (angular, _) { return this.getDimensionKeys(dimensionKeysQuery[1]); } - var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); + var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); if (dimensionValuesQuery) { region = templateSrv.replace(dimensionValuesQuery[1]); namespace = templateSrv.replace(dimensionValuesQuery[2]); metricName = templateSrv.replace(dimensionValuesQuery[3]); - var dimensionPart = templateSrv.replace(dimensionValuesQuery[5]); + var dimensionKey = templateSrv.replace(dimensionValuesQuery[4]); + dimensionPart = templateSrv.replace(dimensionValuesQuery[6]); - var dimensions = {}; - if (!_.isEmpty(dimensionPart)) { - _.each(dimensionPart.split(','), function(v) { - var t = v.split('='); - if (t.length !== 2) { - throw new Error('Invalid query format'); - } - dimensions[t[0]] = t[1]; + dimensions = parseDimensions(dimensionPart); + return this.getDimensionValues(region, namespace, metricName, dimensionKey, dimensions).then(function(result) { + return _.map(result, function(dimension_value) { + return { text: dimension_value }; }); - } + }); + } - return this.getDimensionValues(region, namespace, metricName, dimensions).then(function(result) { + var dimensionsQuery = query.match(/^dimensions\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); + if (dimensionsQuery) { + region = templateSrv.replace(dimensionsQuery[1]); + namespace = templateSrv.replace(dimensionsQuery[2]); + metricName = templateSrv.replace(dimensionsQuery[3]); + dimensionPart = templateSrv.replace(dimensionsQuery[5]); + + dimensions = parseDimensions(dimensionPart); + return this.getDimensions(region, namespace, metricName, dimensions).then(function(result) { return _.map(result, function(dimensions) { var values = _.chain(dimensions) .sortBy(function(dimension) { @@ -228,7 +262,7 @@ function (angular, _) { var metricName = 'EstimatedCharges'; var dimensions = {}; - return this.getDimensionValues(region, namespace, metricName, dimensions).then(function () { + return this.getDimensions(region, namespace, metricName, dimensions).then(function () { return { status: 'success', message: 'Data source is working', title: 'Success' }; }); }; diff --git a/public/app/plugins/datasource/cloudwatch/query_ctrl.js b/public/app/plugins/datasource/cloudwatch/query_ctrl.js index 7bcc73b4323..d0f6fe5b52a 100644 --- a/public/app/plugins/datasource/cloudwatch/query_ctrl.js +++ b/public/app/plugins/datasource/cloudwatch/query_ctrl.js @@ -85,25 +85,11 @@ function (angular, _) { if (segment.type === 'key' || segment.type === 'plus-button') { query = $scope.datasource.getDimensionKeys($scope.target.namespace); } else if (segment.type === 'value') { - query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, {}); + var dimensionKey = $scope.dimSegments[$index-2].value; + query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, {}); } - return query.then(function(results) { - if (segment.type === 'value') { - results = _.chain(results) - .flatten(true) - .filter(function(dimension) { - return dimension.Name === templateSrv.replace($scope.dimSegments[$index-2].value); - }) - .pluck('Value') - .uniq() - .map(function(value) { - return {value: value, text: value}; - }) - .value(); - } - return $scope.transformToSegments(true)(results); - }).then(function(results) { + return query.then($scope.transformToSegments(true)).then(function(results) { if (segment.type === 'key') { results.splice(0, 0, angular.copy($scope.removeDimSegment)); } diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts index a6d4330a37e..6c55eab55ca 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts @@ -146,7 +146,7 @@ describe('CloudWatchDatasource', function() { }); }); - describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization)', scenario => { + describeMetricFindQuery('dimensions(us-east-1,AWS/EC2,CPUUtilization)', scenario => { scenario.setup(() => { scenario.requestResponse = { Metrics: [ @@ -170,4 +170,28 @@ describe('CloudWatchDatasource', function() { }); }); + describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', scenario => { + scenario.setup(() => { + scenario.requestResponse = { + Metrics: [ + { + Namespace: 'AWS/EC2', + MetricName: 'CPUUtilization', + Dimensions: [ + { + Name: 'InstanceId', + Value: 'i-12345678' + } + ] + } + ] + }; + }); + + it('should call __ListMetrics and return result', () => { + expect(scenario.result[0].text).to.be('i-12345678'); + expect(scenario.request.data.action).to.be('ListMetrics'); + }); + }); + }); From 1bbd0567975c266f7884ee9b45acf3a4090e1511 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Mon, 16 Nov 2015 16:47:28 +0900 Subject: [PATCH 013/122] fix templating --- .../app/plugins/datasource/cloudwatch/datasource.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index 4512aed972b..9b4bed35e90 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -135,7 +135,12 @@ function (angular, _) { .filter(function(dimension) { return dimension.Name === dimensionKey; }) - .pluck('Value').uniq().sortBy().value(); + .pluck('Value') + .uniq() + .sortBy() + .map(function(value) { + return {value: value, text: value}; + }).value(); }); }; @@ -204,11 +209,7 @@ function (angular, _) { dimensionPart = templateSrv.replace(dimensionValuesQuery[6]); dimensions = parseDimensions(dimensionPart); - return this.getDimensionValues(region, namespace, metricName, dimensionKey, dimensions).then(function(result) { - return _.map(result, function(dimension_value) { - return { text: dimension_value }; - }); - }); + return this.getDimensionValues(region, namespace, metricName, dimensionKey, dimensions); } var dimensionsQuery = query.match(/^dimensions\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); From ae7e7e96565055dadfca9fbbcaf42428d37c23ff Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Tue, 17 Nov 2015 22:49:46 +0900 Subject: [PATCH 014/122] remove getDimensions() --- .../datasource/cloudwatch/datasource.js | 37 ++----------------- .../cloudwatch/specs/datasource_specs.ts | 24 ------------ 2 files changed, 4 insertions(+), 57 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index 9b4bed35e90..7297346b33c 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -112,7 +112,7 @@ function (angular, _) { }); }; - CloudWatchDatasource.prototype.getDimensions = function(region, namespace, metricName, filterDimensions) { + CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) { var request = { region: templateSrv.replace(region), action: 'ListMetrics', @@ -124,13 +124,8 @@ function (angular, _) { }; return this.awsRequest(request).then(function(result) { - return _.pluck(result.Metrics, 'Dimensions'); - }); - }; - - CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) { - return this.getDimensions(region, namespace, metricName, filterDimensions).then(function(dimensions) { - return _.chain(dimensions) + return _.chain(result.Metrics) + .pluck('Dimensions') .flatten() .filter(function(dimension) { return dimension.Name === dimensionKey; @@ -212,30 +207,6 @@ function (angular, _) { return this.getDimensionValues(region, namespace, metricName, dimensionKey, dimensions); } - var dimensionsQuery = query.match(/^dimensions\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); - if (dimensionsQuery) { - region = templateSrv.replace(dimensionsQuery[1]); - namespace = templateSrv.replace(dimensionsQuery[2]); - metricName = templateSrv.replace(dimensionsQuery[3]); - dimensionPart = templateSrv.replace(dimensionsQuery[5]); - - dimensions = parseDimensions(dimensionPart); - return this.getDimensions(region, namespace, metricName, dimensions).then(function(result) { - return _.map(result, function(dimensions) { - var values = _.chain(dimensions) - .sortBy(function(dimension) { - return dimension.Name; - }) - .map(function(dimension) { - return dimension.Name + '=' + dimension.Value; - }) - .value().join(','); - - return { text: values }; - }); - }); - } - var ebsVolumeIdsQuery = query.match(/^ebs_volume_ids\(([^,]+?),\s?([^,]+?)\)/); if (ebsVolumeIdsQuery) { region = templateSrv.replace(ebsVolumeIdsQuery[1]); @@ -263,7 +234,7 @@ function (angular, _) { var metricName = 'EstimatedCharges'; var dimensions = {}; - return this.getDimensions(region, namespace, metricName, dimensions).then(function () { + return this.getDimensionValues(region, namespace, metricName, 'ServiceName', dimensions).then(function () { return { status: 'success', message: 'Data source is working', title: 'Success' }; }); }; diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts index 6c55eab55ca..b97dff5ce3b 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts @@ -146,30 +146,6 @@ describe('CloudWatchDatasource', function() { }); }); - describeMetricFindQuery('dimensions(us-east-1,AWS/EC2,CPUUtilization)', scenario => { - scenario.setup(() => { - scenario.requestResponse = { - Metrics: [ - { - Namespace: 'AWS/EC2', - MetricName: 'CPUUtilization', - Dimensions: [ - { - Name: 'InstanceId', - Value: 'i-12345678' - } - ] - } - ] - }; - }); - - it('should call __ListMetrics and return result', () => { - expect(scenario.result[0].text).to.be('InstanceId=i-12345678'); - expect(scenario.request.data.action).to.be('ListMetrics'); - }); - }); - describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', scenario => { scenario.setup(() => { scenario.requestResponse = { From 09ff0429867a75c39a74d086cfc7121e0f17cf9a Mon Sep 17 00:00:00 2001 From: Nick Christus Date: Thu, 19 Nov 2015 21:02:38 -0600 Subject: [PATCH 015/122] updated-list-views: added new table layout to additional pages --- public/app/features/admin/partials/orgs.html | 95 ++++++++++--- public/app/features/admin/partials/users.html | 110 +++++++++++---- .../app/features/org/partials/orgApiKeys.html | 4 +- .../app/features/org/partials/orgUsers.html | 127 ++++++++++++++---- .../features/profile/partials/profile.html | 39 +++--- public/less/filter-table.less | 10 +- 6 files changed, 289 insertions(+), 96 deletions(-) diff --git a/public/app/features/admin/partials/orgs.html b/public/app/features/admin/partials/orgs.html index fe87073eb6c..14a9ad931a2 100644 --- a/public/app/features/admin/partials/orgs.html +++ b/public/app/features/admin/partials/orgs.html @@ -4,31 +4,84 @@ -
        -
        +
        +

        Organizations

        - - - - - - - - - - +
        +
        +
          +
        • Filters:
        • +
        • Id
        • +
        • +
        • Name
        • +
        • +
        • + + + +
        • +
        +
        +
        +
        + +
          +
        • + +
        • +
        • + +
        • +
        • + 0 selected, showing 1 of 1 total +
        • +
        + +
        IdName
        {{org.name}} - - - Edit - -    - - - -
        + + + + + + + + + + + + + +
        IdName
        + + + {{org.name}} + + + Edit + +    + + + +
        diff --git a/public/app/features/admin/partials/users.html b/public/app/features/admin/partials/users.html index 6f8365e75dd..7273be6079f 100644 --- a/public/app/features/admin/partials/users.html +++ b/public/app/features/admin/partials/users.html @@ -5,38 +5,92 @@ -
        -
        +
        +

        Users

        - - - - - - - - - - - - - - - - - +
        +
        +
          +
        • Filters:
        • +
        • Id
        • +
        • +
        • Name
        • +
        • +
        • + + + +
        • +
        +
        +
        +
        + +
          +
        • + +
        • +
        • + +
        • +
        • + 0 selected, showing 1 of 1 total +
        • +
        + +
        IdNameLoginEmailGrafana Admin
        {{user.id}}{{user.name}}{{user.login}}{{user.email}}{{user.isAdmin}} - - - Edit - -    - - - -
        + + + + + + + + + + + + + + + + + + + + + +
        IdNameLoginEmailGrafana Admin
        + + + {{user.id}}{{user.name}}{{user.login}}{{user.email}}{{user.isAdmin}} + + + Edit + +    + + + +
        diff --git a/public/app/features/org/partials/orgApiKeys.html b/public/app/features/org/partials/orgApiKeys.html index c24b5c53ec1..cb1c13f64a1 100644 --- a/public/app/features/org/partials/orgApiKeys.html +++ b/public/app/features/org/partials/orgApiKeys.html @@ -5,7 +5,7 @@
        -
        +

        API Keys

        @@ -93,7 +93,7 @@
        {{t.name}} {{t.role}} + diff --git a/public/app/features/org/partials/orgUsers.html b/public/app/features/org/partials/orgUsers.html index 3cb560bd560..dc0ad562b4f 100644 --- a/public/app/features/org/partials/orgUsers.html +++ b/public/app/features/org/partials/orgUsers.html @@ -5,7 +5,7 @@
        -
        +

        Organization users

        @@ -67,6 +67,7 @@ + @@ -74,6 +75,10 @@ +
        Login Email Role
        + + + {{user.login}} {{user.email}} @@ -89,36 +94,100 @@
        -
        - {{invite.email}} - {{invite.name}} - - -   - - - - - -
        - {{invite.url}}
        - -   - - - Invited: {{invite.createdOn | date: 'shortDate'}} by {{invite.invitedBy}} - -
        -
        + +
        +
        +
          +
        • Filters:
        • +
        • Email
        • +
        • +
        • Name
        • +
        • +
        • + + + +
        • +
        +
        +
        +
        + +
          +
        • + +
        • +
        • + +
        • +
        • + 0 selected, showing 1 of 1 total +
        • +
        + + + + + + + + + + + + + + + + + + + + + + +
        EmailName
        + + + {{invite.email}}{{invite.name}} + +   + + + + +
        + {{invite.url}}

        + +   + + + Invited: {{invite.createdOn | date: 'shortDate'}} by {{invite.invitedBy}} + +
        -
        diff --git a/public/app/features/profile/partials/profile.html b/public/app/features/profile/partials/profile.html index d246b4d3914..56eddad92be 100644 --- a/public/app/features/profile/partials/profile.html +++ b/public/app/features/profile/partials/profile.html @@ -5,8 +5,8 @@ -
        -
        +
        +

        Profile

        @@ -62,19 +62,28 @@

        Organizations

        - - - - - - +
        Name: {{org.name}}Role: {{org.role}} - - Current - - - Select - -
        + + + + + + + + + + + + + +
        NameRole
        Name: {{org.name}}Role: {{org.role}} + + Current + + + Select + +
        diff --git a/public/less/filter-table.less b/public/less/filter-table.less index 765fab5662f..99b7a3463d8 100644 --- a/public/less/filter-table.less +++ b/public/less/filter-table.less @@ -13,8 +13,8 @@ .filter-table { width: 100%; - // table-layout: fixed; border-collapse: collapse; + table-layout: fixed; } .filter-table tr { @@ -47,3 +47,11 @@ overflow: hidden; text-overflow: ellipsis; } + +.filter-table .expanded { + border-color: @grafanaPanelBackground; +} + +.filter-table .expanded > td { + padding-bottom: 0; +} From ada9bfcae8140f53bd12139a58fc90a636029212 Mon Sep 17 00:00:00 2001 From: Mauro Stettler Date: Sun, 22 Nov 2015 21:39:56 +0900 Subject: [PATCH 016/122] keep track of elastic search version and generate query according to version --- public/app/features/org/datasourceEditCtrl.js | 6 ++++++ .../plugins/datasource/elasticsearch/datasource.js | 4 +++- .../datasource/elasticsearch/partials/config.html | 13 ++++++++++++- .../datasource/elasticsearch/query_builder.js | 11 +++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/public/app/features/org/datasourceEditCtrl.js b/public/app/features/org/datasourceEditCtrl.js index e2d5cc3d75d..4d17707792f 100644 --- a/public/app/features/org/datasourceEditCtrl.js +++ b/public/app/features/org/datasourceEditCtrl.js @@ -24,6 +24,12 @@ function (angular, _, config) { {name: 'Yearly', value: 'Yearly', example: '[logstash-]YYYY'}, ]; + $scope.elasticsearchVersions = [ + {name: '0.x', value: 0}, + {name: '1.x', value: 1}, + {name: '2.x', value: 2}, + ]; + $scope.init = function() { $scope.isNew = true; $scope.datasources = []; diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 9c749b9459e..6f68951e06c 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -23,9 +23,11 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes this.name = datasource.name; this.index = datasource.index; this.timeField = datasource.jsonData.timeField; + this.elasticsearchVersion = datasource.jsonData.elasticsearchVersion; this.indexPattern = new IndexPattern(datasource.index, datasource.jsonData.interval); this.queryBuilder = new ElasticQueryBuilder({ - timeField: this.timeField + timeField: this.timeField, + elasticsearchVersion: this.elasticsearchVersion }); } diff --git a/public/app/plugins/datasource/elasticsearch/partials/config.html b/public/app/plugins/datasource/elasticsearch/partials/config.html index d1cb05801d6..ef596a4deef 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/config.html +++ b/public/app/plugins/datasource/elasticsearch/partials/config.html @@ -20,7 +20,7 @@
        -
        +
        • Time field name @@ -31,3 +31,14 @@
        +
        +
          +
        • + Elasticsearch version +
        • +
        • + +
        • +
        +
        +
        diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.js b/public/app/plugins/datasource/elasticsearch/query_builder.js index 129c52d3f02..f67cc716a42 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.js +++ b/public/app/plugins/datasource/elasticsearch/query_builder.js @@ -6,11 +6,18 @@ function (angular) { function ElasticQueryBuilder(options) { this.timeField = options.timeField; + this.elasticsearchVersion = options.elasticsearchVersion; } ElasticQueryBuilder.prototype.getRangeFilter = function() { var filter = {}; filter[this.timeField] = {"gte": "$timeFrom", "lte": "$timeTo"}; + + // elastic search versions above 2.0 require the time format to be specified + if (this.elasticsearchVersion >= 2) { + filter[this.timeField]["format"] = "epoch_millis"; + } + return filter; }; @@ -129,6 +136,10 @@ function (angular) { "min_doc_count": 0, "extended_bounds": { "min": "$timeFrom", "max": "$timeTo" } }; + // elastic search versions above 2.0 require the time format to be specified + if (this.elasticsearchVersion >= 2) { + esAgg["date_histogram"]["format"] = "epoch_millis"; + } break; } case 'filters': { From a30ceefa6bacff9936972f41e77070d04005d2d5 Mon Sep 17 00:00:00 2001 From: Mauro Stettler Date: Wed, 25 Nov 2015 16:23:28 +0900 Subject: [PATCH 017/122] add tests for elastic search versioning in query builder and make es version 2 default --- public/app/features/org/datasourceEditCtrl.js | 2 +- .../datasource/elasticsearch/query_builder.js | 4 +-- .../specs/query_builder_specs.ts | 33 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/public/app/features/org/datasourceEditCtrl.js b/public/app/features/org/datasourceEditCtrl.js index 4d17707792f..dd526f69308 100644 --- a/public/app/features/org/datasourceEditCtrl.js +++ b/public/app/features/org/datasourceEditCtrl.js @@ -13,7 +13,7 @@ function (angular, _, config) { $scope.httpConfigPartialSrc = 'app/features/org/partials/datasourceHttpConfig.html'; - var defaults = {name: '', type: 'graphite', url: '', access: 'proxy' }; + var defaults = {name: '', type: 'graphite', url: '', access: 'proxy', jsonData: {'elasticsearchVersion': 2} }; $scope.indexPatternTypes = [ {name: 'No pattern', value: undefined}, diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.js b/public/app/plugins/datasource/elasticsearch/query_builder.js index f67cc716a42..045df314b33 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.js +++ b/public/app/plugins/datasource/elasticsearch/query_builder.js @@ -13,7 +13,7 @@ function (angular) { var filter = {}; filter[this.timeField] = {"gte": "$timeFrom", "lte": "$timeTo"}; - // elastic search versions above 2.0 require the time format to be specified + // elastic search versions 2.x require the time format to be specified if (this.elasticsearchVersion >= 2) { filter[this.timeField]["format"] = "epoch_millis"; } @@ -136,7 +136,7 @@ function (angular) { "min_doc_count": 0, "extended_bounds": { "min": "$timeFrom", "max": "$timeTo" } }; - // elastic search versions above 2.0 require the time format to be specified + // elastic search versions 2.x require the time format to be specified if (this.elasticsearchVersion >= 2) { esAgg["date_histogram"]["format"] = "epoch_millis"; } diff --git a/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts index bcae7d6e852..25aab0a084c 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts @@ -44,6 +44,39 @@ describe('ElasticQueryBuilder', function() { expect(query.aggs["2"].aggs["3"].date_histogram.field).to.be("@timestamp"); }); + it('with es1.x and es2.x date histogram queries check time format', function() { + var builder_2x = new ElasticQueryBuilder({ + timeField: '@timestamp', + elasticsearchVersion: 2 + }); + + var query_params = { + metrics: [], + bucketAggs: [ + {type: 'date_histogram', field: '@timestamp', id: '1'} + ], + }; + + // format should not be specified in 1.x queries + expect("format" in builder.build(query_params)["aggs"]["1"]["date_histogram"]).to.be(false); + + // 2.x query should specify format to be "epoch_millis" + expect(builder_2x.build(query_params)["aggs"]["1"]["date_histogram"]["format"]).to.be("epoch_millis"); + }); + + it('with es1.x and es2.x range filter check time format', function() { + var builder_2x = new ElasticQueryBuilder({ + timeField: '@timestamp', + elasticsearchVersion: 2 + }); + + // format should not be specified in 1.x queries + expect("format" in builder.getRangeFilter()["@timestamp"]).to.be(false); + + // 2.x query should specify format to be "epoch_millis" + expect(builder_2x.getRangeFilter()["@timestamp"]["format"]).to.be("epoch_millis"); + }); + it('with select field', function() { var query = builder.build({ metrics: [{type: 'avg', field: '@value', id: '1'}], From 1bb1ddcd2956a8dd58a745df07f9edb0f2de4c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Kr=C3=B6ll?= Date: Wed, 2 Dec 2015 11:13:57 +0100 Subject: [PATCH 018/122] Fixed spelling error --- public/app/plugins/datasource/elasticsearch/datasource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 9c749b9459e..c41fe0fcd12 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -107,7 +107,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes for (var i = 0; i < fieldNames.length; i++) { fieldValue = fieldValue[fieldNames[i]]; if (!fieldValue) { - console.log('could not find field in annotatation: ', fieldName); + console.log('could not find field in annotation: ', fieldName); return ''; } } From 579bc1c2c8319df3c4bf95eca85c546c03fdd3be Mon Sep 17 00:00:00 2001 From: Piotr Popieluch Date: Thu, 3 Dec 2015 09:23:14 +0100 Subject: [PATCH 019/122] Add more info in route logging - Add remote address - Add method - Add protocol - Add response size - Use consistent unit for response time (us) --- pkg/middleware/logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/middleware/logger.go b/pkg/middleware/logger.go index eb5c7b8dde4..4b8e1f06bae 100644 --- a/pkg/middleware/logger.go +++ b/pkg/middleware/logger.go @@ -32,7 +32,7 @@ func Logger() macaron.Handler { rw := res.(macaron.ResponseWriter) c.Next() - content := fmt.Sprintf("Completed %s %v %s in %v", req.URL.Path, rw.Status(), http.StatusText(rw.Status()), time.Since(start)) + content := fmt.Sprintf("Completed %s \"%s %s %s\" %v %s %d bytes in %dus", c.RemoteAddr(), req.Method, req.URL.Path, req.Proto, rw.Status(), http.StatusText(rw.Status()), rw.Size(), time.Since(start)/time.Microsecond) switch rw.Status() { case 200, 304: From 207c1a20ee2d9093ef77aba2a76e0cc71a17ad10 Mon Sep 17 00:00:00 2001 From: Piotr Popieluch Date: Thu, 3 Dec 2015 11:05:50 +0100 Subject: [PATCH 020/122] router logger, log username taken from cookie --- pkg/middleware/logger.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/middleware/logger.go b/pkg/middleware/logger.go index 4b8e1f06bae..38262de573d 100644 --- a/pkg/middleware/logger.go +++ b/pkg/middleware/logger.go @@ -32,7 +32,12 @@ func Logger() macaron.Handler { rw := res.(macaron.ResponseWriter) c.Next() - content := fmt.Sprintf("Completed %s \"%s %s %s\" %v %s %d bytes in %dus", c.RemoteAddr(), req.Method, req.URL.Path, req.Proto, rw.Status(), http.StatusText(rw.Status()), rw.Size(), time.Since(start)/time.Microsecond) + uname := c.GetCookie(setting.CookieUserName) + if len(uname) == 0 { + uname = "-" + } + + content := fmt.Sprintf("Completed %s %s \"%s %s %s\" %v %s %d bytes in %dus", c.RemoteAddr(), uname, req.Method, req.URL.Path, req.Proto, rw.Status(), http.StatusText(rw.Status()), rw.Size(), time.Since(start)/time.Microsecond) switch rw.Status() { case 200, 304: From efbbb313702dc0f208b2fc8545c5a205983fbd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 3 Dec 2015 12:03:06 +0100 Subject: [PATCH 021/122] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99854966938..3886c32a971 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Replace X.Y.Z by actual version number. cd $GOPATH/src/github.com/grafana/grafana go run build.go setup (only needed once to install godep) godep restore (will pull down all golang lib dependencies in your current GOPATH) -godep go run build.go build +go run build.go build ``` ### Building frontend assets From d6935847b4ebad698684b9428f0982baf8604bf6 Mon Sep 17 00:00:00 2001 From: Alexey Larkov Date: Thu, 3 Dec 2015 17:36:29 +0500 Subject: [PATCH 022/122] Web. Fix double slash --- public/app/plugins/datasource/elasticsearch/datasource.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 9c749b9459e..bd1773028fb 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -94,7 +94,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes var payload = angular.toJson(header) + '\n' + angular.toJson(data) + '\n'; - return this._post('/_msearch', payload).then(function(res) { + return this._post('_msearch', payload).then(function(res) { var list = []; var hits = res.responses[0].hits.hits; @@ -188,7 +188,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes payload = payload.replace(/\$timeTo/g, options.range.to.valueOf()); payload = templateSrv.replace(payload, options.scopedVars); - return this._post('/_msearch', payload).then(function(res) { + return this._post('_msearch', payload).then(function(res) { return new ElasticResponse(sentTargets, res).getTimeSeries(); }); }; From cf1f43dc9de5c66572d16cc89ca7b6e13511ad0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 3 Dec 2015 15:09:39 +0100 Subject: [PATCH 023/122] feat(influxdb): support for table queries, closes #3409, #3219 --- .../app/{panels/table => core}/table_model.ts | 23 +++------- public/app/panels/table/controller.ts | 20 ++++++++- .../app/panels/table/specs/renderer_specs.ts | 2 +- .../panels/table/specs/transformers_specs.ts | 13 +++--- public/app/panels/table/transformers.ts | 40 +++++++++++++++++- .../plugins/datasource/influxdb/datasource.js | 24 ++++++++--- .../datasource/influxdb/influx_query.ts | 2 + .../datasource/influxdb/influx_series.js | 42 ++++++++++++++++++- .../influxdb/partials/query.editor.html | 6 +++ .../plugins/datasource/influxdb/query_ctrl.js | 5 +++ .../influxdb/specs/influx_series_specs.ts | 23 ++++++++++ .../specs => test/core}/table_model_specs.ts | 2 +- 12 files changed, 166 insertions(+), 36 deletions(-) rename public/app/{panels/table => core}/table_model.ts (56%) rename public/{app/panels/table/specs => test/core}/table_model_specs.ts (95%) diff --git a/public/app/panels/table/table_model.ts b/public/app/core/table_model.ts similarity index 56% rename from public/app/panels/table/table_model.ts rename to public/app/core/table_model.ts index 1fa4007e6e3..7eb8d5ad92a 100644 --- a/public/app/panels/table/table_model.ts +++ b/public/app/core/table_model.ts @@ -1,12 +1,13 @@ -import {transformers} from './transformers'; -export class TableModel { +class TableModel { columns: any[]; rows: any[]; + type: string; constructor() { this.columns = []; this.rows = []; + this.type = 'table'; } sort(options) { @@ -33,20 +34,6 @@ export class TableModel { this.columns[options.col].desc = true; } } - - static transform(data, panel) { - var model = new TableModel(); - - if (!data || data.length === 0) { - return model; - } - - var transformer = transformers[panel.transform]; - if (!transformer) { - throw {message: 'Transformer ' + panel.transformer + ' not found'}; - } - - transformer.transform(data, panel, model); - return model; - } } + +export = TableModel; diff --git a/public/app/panels/table/controller.ts b/public/app/panels/table/controller.ts index 09e77108631..270e2f65a3d 100644 --- a/public/app/panels/table/controller.ts +++ b/public/app/panels/table/controller.ts @@ -5,7 +5,7 @@ import _ = require('lodash'); import moment = require('moment'); import PanelMeta = require('app/features/panel/panel_meta'); -import {TableModel} from './table_model'; +import {transformDataToTable} from './transformers'; export class TablePanelCtrl { @@ -104,7 +104,23 @@ export class TablePanelCtrl { }; $scope.render = function() { - $scope.table = TableModel.transform($scope.dataRaw, $scope.panel); + // automatically correct transform mode + // based on data + if ($scope.dataRaw && $scope.dataRaw.length) { + if ($scope.dataRaw[0].type === 'table') { + $scope.panel.transform = 'table'; + } else { + if ($scope.dataRaw[0].type === 'docs') { + $scope.panel.transform = 'json'; + } else { + if ($scope.panel.transform === 'table' || $scope.panel.transform === 'json') { + $scope.panel.transform = 'timeseries_to_rows'; + } + } + } + } + + $scope.table = transformDataToTable($scope.dataRaw, $scope.panel); $scope.table.sort($scope.panel.sort); panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw); }; diff --git a/public/app/panels/table/specs/renderer_specs.ts b/public/app/panels/table/specs/renderer_specs.ts index f8fdebb9ab0..f8af1baba17 100644 --- a/public/app/panels/table/specs/renderer_specs.ts +++ b/public/app/panels/table/specs/renderer_specs.ts @@ -1,6 +1,6 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; -import {TableModel} from '../table_model'; +import TableModel = require('app/core/table_model'); import {TableRenderer} from '../renderer'; describe('when rendering table', () => { diff --git a/public/app/panels/table/specs/transformers_specs.ts b/public/app/panels/table/specs/transformers_specs.ts index bb42b997d33..e3cdf44c8b2 100644 --- a/public/app/panels/table/specs/transformers_specs.ts +++ b/public/app/panels/table/specs/transformers_specs.ts @@ -1,7 +1,6 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; -import {TableModel} from '../table_model'; -import {transformers} from '../transformers'; +import {transformers, transformDataToTable} from '../transformers'; describe('when transforming time series table', () => { var table; @@ -26,7 +25,7 @@ describe('when transforming time series table', () => { }; beforeEach(() => { - table = TableModel.transform(timeSeries, panel); + table = transformDataToTable(timeSeries, panel); }); it('should return 3 rows', () => { @@ -51,7 +50,7 @@ describe('when transforming time series table', () => { }; beforeEach(() => { - table = TableModel.transform(timeSeries, panel); + table = transformDataToTable(timeSeries, panel); }); it ('should return 3 columns', () => { @@ -80,7 +79,7 @@ describe('when transforming time series table', () => { }; beforeEach(() => { - table = TableModel.transform(timeSeries, panel); + table = transformDataToTable(timeSeries, panel); }); it('should return 2 rows', () => { @@ -133,7 +132,7 @@ describe('when transforming time series table', () => { describe('transform', function() { beforeEach(() => { - table = TableModel.transform(rawData, panel); + table = transformDataToTable(rawData, panel); }); it ('should return 2 columns', () => { @@ -164,7 +163,7 @@ describe('when transforming time series table', () => { ]; beforeEach(() => { - table = TableModel.transform(rawData, panel); + table = transformDataToTable(rawData, panel); }); it ('should return 4 columns', () => { diff --git a/public/app/panels/table/transformers.ts b/public/app/panels/table/transformers.ts index a4d0d4395c5..843eb83c034 100644 --- a/public/app/panels/table/transformers.ts +++ b/public/app/panels/table/transformers.ts @@ -4,6 +4,7 @@ import moment = require('moment'); import _ = require('lodash'); import flatten = require('app/core/utils/flatten'); import TimeSeries = require('app/core/time_series'); +import TableModel = require('app/core/table_model'); var transformers = {}; @@ -136,6 +137,27 @@ transformers['annotations'] = { } }; +transformers['table'] = { + description: 'Table', + getColumns: function(data) { + if (!data || data.length === 0) { + return []; + } + }, + transform: function(data, panel, model) { + if (!data || data.length === 0) { + return; + } + + if (data[0].type !== 'table') { + throw {message: 'Query result is not in table format, try using another transform.'}; + } + + model.columns = data[0].columns; + model.rows = data[0].rows; + } +}; + transformers['json'] = { description: 'JSON Data', getColumns: function(data) { @@ -197,4 +219,20 @@ transformers['json'] = { } }; -export {transformers} +function transformDataToTable(data, panel) { + var model = new TableModel(); + + if (!data || data.length === 0) { + return model; + } + + var transformer = transformers[panel.transform]; + if (!transformer) { + throw {message: 'Transformer ' + panel.transformer + ' not found'}; + } + + transformer.transform(data, panel, model); + return model; +} + +export {transformers, transformDataToTable} diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js index 9adabe9a83f..a23937cd74c 100644 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ b/public/app/plugins/datasource/influxdb/datasource.js @@ -53,6 +53,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { // replace templated variables allQueries = templateSrv.replace(allQueries, options.scopedVars); + return this._seriesQuery(allQueries).then(function(data) { if (!data || !data.results) { return []; @@ -63,13 +64,26 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { var result = data.results[i]; if (!result || !result.series) { continue; } - var alias = (queryTargets[i] || {}).alias; + var target = queryTargets[i]; + var alias = target.alias; if (alias) { - alias = templateSrv.replace(alias, options.scopedVars); + alias = templateSrv.replace(target.alias, options.scopedVars); } - var targetSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }).getTimeSeries(); - for (y = 0; y < targetSeries.length; y++) { - seriesList.push(targetSeries[y]); + + var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); + + switch(target.resultFormat) { + case 'table': { + seriesList.push(influxSeries.getTable()); + break; + } + default: { + var timeSeries = influxSeries.getTimeSeries(); + for (y = 0; y < timeSeries.length; y++) { + seriesList.push(timeSeries[y]); + } + break; + } } } diff --git a/public/app/plugins/datasource/influxdb/influx_query.ts b/public/app/plugins/datasource/influxdb/influx_query.ts index 34b86e16930..f50627c7f89 100644 --- a/public/app/plugins/datasource/influxdb/influx_query.ts +++ b/public/app/plugins/datasource/influxdb/influx_query.ts @@ -12,6 +12,8 @@ class InfluxQuery { constructor(target) { this.target = target; + target.dsType = 'influxdb'; + target.resultFormat = target.resultFormat || 'time_series'; target.tags = target.tags || []; target.groupBy = target.groupBy || [ {type: 'time', params: ['$interval']}, diff --git a/public/app/plugins/datasource/influxdb/influx_series.js b/public/app/plugins/datasource/influxdb/influx_series.js index fff3536b5e8..63495ffb9b0 100644 --- a/public/app/plugins/datasource/influxdb/influx_series.js +++ b/public/app/plugins/datasource/influxdb/influx_series.js @@ -1,7 +1,8 @@ define([ 'lodash', + 'app/core/table_model', ], -function (_) { +function (_, TableModel) { 'use strict'; function InfluxSeries(options) { @@ -108,5 +109,44 @@ function (_) { return list; }; + p.getTable = function() { + var table = new TableModel(); + var self = this; + var i, j; + + if (self.series.length === 0) { + return table; + } + + _.each(self.series, function(series, seriesIndex) { + + if (seriesIndex === 0) { + table.columns.push({text: 'Time', type: 'time'}); + _.each(_.keys(series.tags), function(key) { + table.columns.push({text: key}); + }); + for (j = 1; j < series.columns.length; j++) { + table.columns.push({text: series.columns[j]}); + } + } + + if (series.values) { + for (i = 0; i < series.values.length; i++) { + var values = series.values[i]; + if (series.tags) { + for (var key in series.tags) { + if (series.tags.hasOwnProperty(key)) { + values.splice(1, 0, series.tags[key]); + } + } + } + table.rows.push(values); + } + } + }); + + return table; + }; + return InfluxSeries; }); diff --git a/public/app/plugins/datasource/influxdb/partials/query.editor.html b/public/app/plugins/datasource/influxdb/partials/query.editor.html index 0aeb8a44224..2b9f7e1a620 100644 --- a/public/app/plugins/datasource/influxdb/partials/query.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/query.editor.html @@ -103,6 +103,12 @@
      • +
      • + Format as +
      • +
      • + +
      • diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.js b/public/app/plugins/datasource/influxdb/query_ctrl.js index 38f87ecd84e..52b7e7f1b7a 100644 --- a/public/app/plugins/datasource/influxdb/query_ctrl.js +++ b/public/app/plugins/datasource/influxdb/query_ctrl.js @@ -20,6 +20,11 @@ function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) { $scope.queryModel = new InfluxQuery($scope.target); $scope.queryBuilder = new InfluxQueryBuilder($scope.target); $scope.groupBySegment = uiSegmentSrv.newPlusButton(); + $scope.resultFormats = [ + {text: 'Time series', value: 'time_series'}, + {text: 'Table', value: 'table'}, + {text: 'JSON field', value: 'json_field'}, + ]; if (!$scope.target.measurement) { $scope.measurementSegment = uiSegmentSrv.newSelectMeasurement(); diff --git a/public/app/plugins/datasource/influxdb/specs/influx_series_specs.ts b/public/app/plugins/datasource/influxdb/specs/influx_series_specs.ts index c8c127ed759..8352e41d99a 100644 --- a/public/app/plugins/datasource/influxdb/specs/influx_series_specs.ts +++ b/public/app/plugins/datasource/influxdb/specs/influx_series_specs.ts @@ -186,5 +186,28 @@ describe('when generating timeseries from influxdb response', function() { }); }); + describe('given table response', function() { + var options = { + alias: '', + series: [ + { + name: 'app.prod.server1.count', + tags: {}, + columns: ['time', 'datacenter', 'value'], + values: [[1431946625000, 'America', 10], [1431946626000, 'EU', 12]] + } + ] + }; + + it('should return table', function() { + var series = new InfluxSeries(options); + var table = series.getTable(); + + expect(table.type).to.be('table'); + expect(table.columns.length).to.be(3); + expect(table.rows[0]).to.eql([1431946625000, 'America', 10]);; + }); + }); + }); diff --git a/public/app/panels/table/specs/table_model_specs.ts b/public/test/core/table_model_specs.ts similarity index 95% rename from public/app/panels/table/specs/table_model_specs.ts rename to public/test/core/table_model_specs.ts index ad515835730..8cdeb04f8d0 100644 --- a/public/app/panels/table/specs/table_model_specs.ts +++ b/public/test/core/table_model_specs.ts @@ -1,6 +1,6 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; -import {TableModel} from '../table_model'; +import TableModel = require('app/core/table_model'); describe('when sorting table desc', () => { var table; From d7c7f27207fa6a4682383672d664f4e28361a0f7 Mon Sep 17 00:00:00 2001 From: carl bergquist Date: Thu, 3 Dec 2015 15:29:28 +0100 Subject: [PATCH 024/122] add npm-debug.log to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0ac42cbcb4b..3aa23b45149 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules +npm-debug.log coverage/ .aws-config.json awsconfig From 419251ed3514ca4b322ec1bcbed3416711873522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 3 Dec 2015 16:32:35 +0100 Subject: [PATCH 025/122] fix(elasticsearch): fixed issue with default state of elasticsearch query, result in error before query controller could set defaults, moved defaults to query builder, also removed raw query mode as it is pretty broken, fixes #3396 --- CHANGELOG.md | 4 +++- .../plugins/datasource/elasticsearch/datasource.js | 4 ++++ .../elasticsearch/partials/query.editor.html | 1 - .../datasource/elasticsearch/query_builder.js | 11 ++++++----- .../plugins/datasource/elasticsearch/query_ctrl.js | 12 +----------- .../elasticsearch/specs/query_builder_specs.ts | 8 -------- 6 files changed, 14 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b315d6323..4d6fa247b59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ * **Elasticsearch**: Support for dynamic daily indices for annotations, closes [#3061](https://github.com/grafana/grafana/issues/3061) * **Graph Panel**: Option to hide series with all zeroes from legend and tooltip, closes [#1381](https://github.com/grafana/grafana/issues/1381), [#3336](https://github.com/grafana/grafana/issues/3336) - ### Bug Fixes * **cloudwatch**: fix for handling of period for long time ranges, fixes [#3086](https://github.com/grafana/grafana/issues/3086) * **dashboard**: fix for collapse row by clicking on row title, fixes [#3065](https://github.com/grafana/grafana/issues/3065) @@ -16,6 +15,9 @@ * **graph**: layout fix for color picker when right side legend was enabled, fixes [#3093](https://github.com/grafana/grafana/issues/3093) * **elasticsearch**: disabling elastic query (via eye) caused error, fixes [#3300](https://github.com/grafana/grafana/issues/3300) +### Breaking changes +* **elasticsearch**: Manual json edited queries are not supported any more (They very barely worked in 2.5) + # 2.5 (2015-10-28) **New Feature: Mix data sources** diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 9c749b9459e..9307031689c 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -183,6 +183,10 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes sentTargets.push(target); } + if (sentTargets.length === 0) { + return $q.when([]); + } + payload = payload.replace(/\$interval/g, options.interval); payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf()); payload = payload.replace(/\$timeTo/g, options.range.to.valueOf()); diff --git a/public/app/plugins/datasource/elasticsearch/partials/query.editor.html b/public/app/plugins/datasource/elasticsearch/partials/query.editor.html index dee2401e6f3..d027e1a5c14 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/query.editor.html +++ b/public/app/plugins/datasource/elasticsearch/partials/query.editor.html @@ -14,7 +14,6 @@