mirror of
https://github.com/grafana/grafana.git
synced 2025-02-12 00:25:46 -06:00
Merge branch 'master' into v4.2.x
This commit is contained in:
commit
140a0982e8
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,4 +1,17 @@
|
||||
# 4.2.0 (unreleased)
|
||||
# 4.3.0 (unreleased)
|
||||
|
||||
## Minor Enchancements
|
||||
* **Threema**: Add emoji to Threema alert notifications [#7676](https://github.com/grafana/grafana/pull/7676) thx [@dbrgn](https://github.com/dbrgn)
|
||||
* **Panels**: Support dm3 unit [#7695](https://github.com/grafana/grafana/issues/7695) thx [@mitjaziv](https://github.com/mitjaziv)
|
||||
|
||||
# 4.2.0-beta2 (unreleased)
|
||||
## Minor Enhancements
|
||||
* **Templates**: Prevent use of the prefix `__` for templates in web UI [#7678](https://github.com/grafana/grafana/issues/7678)
|
||||
|
||||
## Bugfixes
|
||||
* **Webhook**: Use proxy settings from environment variables [#7710](https://github.com/grafana/grafana/issues/7710)
|
||||
|
||||
# 4.2.0-beta1 (2017-02-27)
|
||||
|
||||
## Enhancements
|
||||
* **Telegram**: Added Telegram alert notifier [#7098](https://github.com/grafana/grafana/pull/7098), thx [@leonoff](https://github.com/leonoff)
|
||||
@ -13,7 +26,7 @@
|
||||
* **Alerting**: Uploading images for alert notifications is now optional [#7419](https://github.com/grafana/grafana/issues/7419)
|
||||
* **Dashboard**: Adds shortcut for collapsing/expanding all rows [#552](https://github.com/grafana/grafana/issues/552), thx [@mtanda](https://github.com/mtanda)
|
||||
* **Alerting**: Adds de duping of alert notifications [#7632](https://github.com/grafana/grafana/pull/7632)
|
||||
* **Orgs**: Sharing dashboards using Grafana share feature will not redirect to correct org. [#1613](https://github.com/grafana/grafana/issues/1613)
|
||||
* **Orgs**: Sharing dashboards using Grafana share feature will now redirect to correct org. [#1613](https://github.com/grafana/grafana/issues/1613)
|
||||
* **Pushover**: Add Pushover alert notifications [#7526](https://github.com/grafana/grafana/pull/7526) thx [@devkid](https://github.com/devkid)
|
||||
* **Threema**: Add Threema Gateway alert notification integration [#7482](https://github.com/grafana/grafana/pull/7482) thx [@dbrgn](https://github.com/dbrgn)
|
||||
|
||||
|
@ -30,7 +30,7 @@ install:
|
||||
build_script:
|
||||
- go run build.go build
|
||||
- grunt release
|
||||
- go run build.go sha1-dist
|
||||
- go run build.go sha-dist
|
||||
- cp dist/* .
|
||||
|
||||
artifacts:
|
||||
|
18
build.go
18
build.go
@ -5,7 +5,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
@ -105,8 +105,8 @@ func main() {
|
||||
grunt(gruntBuildArg("release")...)
|
||||
createDebPackages()
|
||||
|
||||
case "sha1-dist":
|
||||
sha1FilesInDist()
|
||||
case "sha-dist":
|
||||
shaFilesInDist()
|
||||
|
||||
case "latest":
|
||||
makeLatestDistCopies()
|
||||
@ -522,14 +522,14 @@ func md5File(file string) error {
|
||||
return out.Close()
|
||||
}
|
||||
|
||||
func sha1FilesInDist() {
|
||||
func shaFilesInDist() {
|
||||
filepath.Walk("./dist", func(path string, f os.FileInfo, err error) error {
|
||||
if path == "./dist" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.Contains(path, ".sha1") == false {
|
||||
err := sha1File(path)
|
||||
if strings.Contains(path, ".sha256") == false {
|
||||
err := shaFile(path)
|
||||
if err != nil {
|
||||
log.Printf("Failed to create sha file. error: %v\n", err)
|
||||
}
|
||||
@ -538,20 +538,20 @@ func sha1FilesInDist() {
|
||||
})
|
||||
}
|
||||
|
||||
func sha1File(file string) error {
|
||||
func shaFile(file string) error {
|
||||
fd, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
h := sha1.New()
|
||||
h := sha256.New()
|
||||
_, err = io.Copy(h, fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := os.Create(file + ".sha1")
|
||||
out, err := os.Create(file + ".sha256")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ dependencies:
|
||||
|
||||
test:
|
||||
override:
|
||||
- bash scripts/circle-test.sh
|
||||
- bash scripts/circle-test.sh
|
||||
|
||||
deployment:
|
||||
gh_branch:
|
||||
@ -41,7 +41,7 @@ deployment:
|
||||
commands:
|
||||
- ./scripts/build/deploy.sh
|
||||
- ./scripts/build/sign_packages.sh
|
||||
- go run build.go sha1-dist
|
||||
- go run build.go sha-dist
|
||||
- aws s3 sync ./dist s3://$BUCKET_NAME/master
|
||||
- ./scripts/trigger_windows_build.sh ${APPVEYOR_TOKEN} ${CIRCLE_SHA1} master
|
||||
- ./scripts/trigger_docker_build.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN}
|
||||
@ -50,7 +50,7 @@ deployment:
|
||||
commands:
|
||||
- ./scripts/build/deploy.sh
|
||||
- ./scripts/build/sign_packages.sh
|
||||
- go run build.go sha1-dist
|
||||
- go run build.go sha-dist
|
||||
- aws s3 sync ./dist s3://$BUCKET_NAME/release
|
||||
- ./scripts/trigger_windows_build.sh ${APPVEYOR_TOKEN} ${CIRCLE_SHA1} release
|
||||
|
||||
- ./scripts/trigger_docker_build.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN} ${CIRCLE_TAG}
|
||||
|
@ -101,4 +101,9 @@ config file.
|
||||
|
||||
This is an optional requirement, you can get slack and email notifications without setting this up.
|
||||
|
||||
# Configure the link back to Grafana from alert notifications
|
||||
|
||||
All alert notifications contains a link back to the triggered alert in the Grafana instance.
|
||||
This url is based on the [domain](/installation/configuration/#domain) setting in Grafana.
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@ type = "docs"
|
||||
name = "Version 4.1"
|
||||
identifier = "v4.1"
|
||||
parent = "whatsnew"
|
||||
weight = -1
|
||||
weight = 3
|
||||
+++
|
||||
|
||||
|
||||
|
88
docs/sources/guides/whats-new-in-v4-2.md
Normal file
88
docs/sources/guides/whats-new-in-v4-2.md
Normal file
@ -0,0 +1,88 @@
|
||||
+++
|
||||
title = "What's New in Grafana v4.2"
|
||||
description = "Feature & improvement highlights for Grafana v4.2"
|
||||
keywords = ["grafana", "new", "documentation", "4.2.0"]
|
||||
type = "docs"
|
||||
[menu.docs]
|
||||
name = "Version 4.2"
|
||||
identifier = "v4.2"
|
||||
parent = "whatsnew"
|
||||
weight = -1
|
||||
+++
|
||||
|
||||
## Whats new in Grafana v4.2
|
||||
|
||||
Grafana v4.2 Beta is now [available for download](/download/4_2_0/).
|
||||
Just like the last release this one contains lots bug fixes and minor improvements.
|
||||
We are very happy to say that 27 of 40 issues was closed by pull requests from the community.
|
||||
Big thumbs up!
|
||||
|
||||
## Release Highlights
|
||||
|
||||
- **Hipchat**: Adds support for sending alert notifications to hipchat [#6451](https://github.com/grafana/grafana/issues/6451), thx [@jregovic](https://github.com/jregovic)
|
||||
- **Telegram**: Added Telegram alert notifier [#7098](https://github.com/grafana/grafana/pull/7098), thx [@leonoff](https://github.com/leonoff)
|
||||
- **LINE**: Add LINE as alerting notification channel [#7301](https://github.com/grafana/grafana/pull/7301), thx [@huydx](https://github.com/huydx)
|
||||
- **Templating**: Make $__interval and $__interval_ms global built in variables that can be used in by any datasource (in panel queries), closes [#7190](https://github.com/grafana/grafana/issues/7190), closes [#6582](https://github.com/grafana/grafana/issues/6582)
|
||||
- **Alerting**: Adds deduping of alert notifications [#7632](https://github.com/grafana/grafana/pull/7632)
|
||||
- **Alerting**: Better information about why an alert triggered [#7035](https://github.com/grafana/grafana/issues/7035)
|
||||
- **Orgs**: Sharing dashboards using Grafana share feature will now redirect to correct org. [#6948](https://github.com/grafana/grafana/issues/6948)
|
||||
- [Full changelog](https://github.com/grafana/grafana/blob/master/CHANGELOG.md)
|
||||
|
||||
### New alert notification channels
|
||||
|
||||
This release adds **five** new alert notifications channels, all of them contributed by the community.
|
||||
|
||||
* Hipchat
|
||||
* Telegram
|
||||
* LINE
|
||||
* Pushover
|
||||
* Threema
|
||||
|
||||
### Templating
|
||||
|
||||
We added two new global built in variables in grafana. `$__interval` and `$__interval_ms` are now reserved template names in grafana and can be used by any datasource.
|
||||
We might add more global built in variables in the future and if we do we will prefix them with `$__`. So please avoid using that in your template variables.
|
||||
|
||||
### Dedupe alert notifications when running multiple servers
|
||||
|
||||
In this release we will dedupe alert notificiations when you are running multiple servers.
|
||||
This makes it possible to run alerting on multiple servers and only get one notification.
|
||||
|
||||
We currently solve this with sql transactions which puts some limitations for how many servers you can use to execute the same rules.
|
||||
3-5 servers should not be a problem but as always, it depends on how many alerts you have and how frequently they execute.
|
||||
|
||||
Next up for a better HA situation is to add support for workload balancing between Grafana servers.
|
||||
|
||||
### Alerting more info
|
||||
|
||||
You can now see the reason why an alert triggered in the alert history. Its also easier to detect when an alert is set to `alerting` due to the `no_data` option.
|
||||
|
||||
### Improved support for multi-org setup
|
||||
|
||||
When loading dashboards we now set an query parameter called orgId. So we can detect from which org an user shared a dashboard.
|
||||
This makes it possible for users to share dashboards between orgs without changing org first.
|
||||
|
||||
We aim to introduce [dashboard groups](https://github.com/grafana/grafana/issues/1611) sometime in the future which will introduce access control and user groups within one org.
|
||||
Making it possible to have users in multiple groups and have detailed access control.
|
||||
|
||||
## Upgrade & Breaking changes
|
||||
|
||||
If your using https in grafana we now force you to use tls 1.2 and the most secure ciphers.
|
||||
We think its better to be secure by default rather then making it configurable.
|
||||
If you want to run https with lower versions of tls we suggest you put a reserve proxy in front of grafana.
|
||||
|
||||
If you have template variables name `$__interval` or `$__interval_ms` they will no longer work since these keywords
|
||||
are reserved as global built in variables. We might add more global built in variables in the future and if we do, we will prefix them with `$__`. So please avoid using that in your template variables.
|
||||
|
||||
## Changelog
|
||||
|
||||
Checkout the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file for a complete list
|
||||
of new features, changes, and bug fixes.
|
||||
|
||||
## Download
|
||||
|
||||
Head to [v4.2-beta download page](/download/4_2_0/) for download links & instructions.
|
||||
|
||||
## Thanks
|
||||
|
||||
A big thanks to all the Grafana users who contribute by submitting PRs, bug reports & feedback!
|
@ -135,6 +135,10 @@ Path to the certificate file (if `protocol` is set to `https`).
|
||||
|
||||
Path to the certificate key file (if `protocol` is set to `https`).
|
||||
|
||||
### router_logging
|
||||
|
||||
Set to true for Grafana to log all HTTP requests (not just errors). These are logged as Info level events
|
||||
to grafana log.
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
@ -457,7 +461,7 @@ session provider you have configured.
|
||||
|
||||
- **file:** session file path, e.g. `data/sessions`
|
||||
- **mysql:** go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name`
|
||||
- **postgres:** ex: user=a password=b host=localhost port=5432 dbname=c sslmode=disable
|
||||
- **postgres:** ex: user=a password=b host=localhost port=5432 dbname=c sslmode=require
|
||||
- **memcache:** ex: 127.0.0.1:11211
|
||||
- **redis:** ex: `addr=127.0.0.1:6379,pool_size=100,prefix=grafana`
|
||||
|
||||
@ -473,6 +477,17 @@ Mysql Example:
|
||||
PRIMARY KEY (`key`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
Postgres Example:
|
||||
|
||||
CREATE TABLE session (
|
||||
key CHAR(16) NOT NULL,
|
||||
data BYTEA,
|
||||
expiry INTEGER NOT NULL,
|
||||
PRIMARY KEY (key)
|
||||
);
|
||||
|
||||
Postgres valid `sslmode` are `disable`, `require` (default), `verify-ca`, and `verify-full`.
|
||||
|
||||
### cookie_name
|
||||
|
||||
The name of the Grafana session cookie.
|
||||
@ -602,7 +617,7 @@ You can choose between (s3, webdav). If left empty Grafana will ignore the uploa
|
||||
## [external_image_storage.s3]
|
||||
|
||||
### bucket_url
|
||||
Bucket URL for S3. AWS region can be specified within URL or defaults to 'us-east-1', e.g.
|
||||
Bucket URL for S3. AWS region can be specified within URL or defaults to 'us-east-1', e.g.
|
||||
- http://grafana.s3.amazonaws.com/
|
||||
- https://grafana.s3-ap-southeast-2.amazonaws.com/
|
||||
- https://grafana.s3-cn-north-1.amazonaws.com.cn
|
||||
|
@ -16,6 +16,7 @@ weight = 1
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable for Debian-based Linux | [4.1.2 (x86-64 deb)](https://grafanarel.s3.amazonaws.com/builds/grafana_4.1.2-1486989747_amd64.deb)
|
||||
Beta for Debian-based Linux | [4.2.0-beta1 (x86-64 deb)](https://grafanarel.s3.amazonaws.com/builds/grafana_4.2.0-beta1_amd64.deb)
|
||||
|
||||
## Install Stable
|
||||
|
||||
@ -25,6 +26,14 @@ $ sudo apt-get install -y adduser libfontconfig
|
||||
$ sudo dpkg -i grafana_4.1.2-1486989747_amd64.deb
|
||||
```
|
||||
|
||||
## Install Beta
|
||||
|
||||
```
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_4.2.0-beta1_amd64.deb
|
||||
$ sudo apt-get install -y adduser libfontconfig
|
||||
$ sudo dpkg -i grafana_4.2.0-beta1_amd64.deb
|
||||
```
|
||||
|
||||
## APT Repository
|
||||
|
||||
Add the following line to your `/etc/apt/sources.list` file.
|
||||
|
@ -16,6 +16,7 @@ weight = 2
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [4.1.2 (x86-64 rpm)](https://grafanarel.s3.amazonaws.com/builds/grafana-4.1.2-1486989747.x86_64.rpm)
|
||||
Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [4.2.0-beta1 (x86-64 rpm)](https://grafanarel.s3.amazonaws.com/builds/grafana-4.2.0-beta1.x86_64.rpm)
|
||||
|
||||
## Install Stable
|
||||
|
||||
|
@ -14,6 +14,7 @@ weight = 3
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Latest stable package for Windows | [grafana.4.1.2.windows-x64.zip](https://grafanarel.s3.amazonaws.com/builds/grafana-4.1.2.windows-x64.zip)
|
||||
Latest beta package for Windows | [grafana-4.2.0-beta1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/builds/grafana-4.2.0-beta1.windows-x64.zip)
|
||||
|
||||
## Configure
|
||||
|
||||
|
@ -114,7 +114,10 @@ func getCredentials(dsInfo *datasourceInfo) (*credentials.Credentials, error) {
|
||||
DurationSeconds: aws.Int64(900),
|
||||
}
|
||||
|
||||
stsSess := session.New()
|
||||
stsSess, err := session.NewSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stsCreds := credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
@ -126,7 +129,11 @@ func getCredentials(dsInfo *datasourceInfo) (*credentials.Credentials, error) {
|
||||
Credentials: stsCreds,
|
||||
}
|
||||
|
||||
svc := sts.New(session.New(stsConfig), stsConfig)
|
||||
sess, err := session.NewSession(stsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
svc := sts.New(sess, stsConfig)
|
||||
resp, err := svc.AssumeRole(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -139,7 +146,10 @@ func getCredentials(dsInfo *datasourceInfo) (*credentials.Credentials, error) {
|
||||
}
|
||||
}
|
||||
|
||||
sess := session.New()
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
creds := credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.StaticProvider{Value: credentials.Value{
|
||||
@ -185,7 +195,12 @@ func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(sess, cfg)
|
||||
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
@ -232,7 +247,12 @@ func handleListMetrics(req *cwRequest, c *middleware.Context) {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(sess, cfg)
|
||||
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
@ -273,7 +293,12 @@ func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(sess, cfg)
|
||||
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
@ -316,7 +341,12 @@ func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(sess, cfg)
|
||||
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
@ -360,7 +390,12 @@ func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := cloudwatch.New(sess, cfg)
|
||||
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
@ -396,7 +431,12 @@ func handleDescribeInstances(req *cwRequest, c *middleware.Context) {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := ec2.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to call AWS API", err)
|
||||
return
|
||||
}
|
||||
svc := ec2.New(sess, cfg)
|
||||
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
|
@ -258,8 +258,11 @@ func getAllMetrics(cwData *datasourceInfo) (cloudwatch.ListMetricsOutput, error)
|
||||
Region: aws.String(cwData.Region),
|
||||
Credentials: creds,
|
||||
}
|
||||
|
||||
svc := cloudwatch.New(session.New(cfg), cfg)
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
return cloudwatch.ListMetricsOutput{}, err
|
||||
}
|
||||
svc := cloudwatch.New(sess, cfg)
|
||||
|
||||
params := &cloudwatch.ListMetricsInput{
|
||||
Namespace: aws.String(cwData.Namespace),
|
||||
|
@ -35,7 +35,10 @@ func NewS3Uploader(region, bucket, acl, accessKey, secretKey string) *S3Uploader
|
||||
}
|
||||
|
||||
func (u *S3Uploader) Upload(imageDiskPath string) (string, error) {
|
||||
sess := session.New()
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
creds := credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.StaticProvider{Value: credentials.Value{
|
||||
@ -58,7 +61,11 @@ func (u *S3Uploader) Upload(imageDiskPath string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
svc := s3.New(session.New(cfg), cfg)
|
||||
sess, err = session.NewSession(cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
svc := s3.New(sess, cfg)
|
||||
params := &s3.PutObjectInput{
|
||||
Bucket: aws.String(u.bucket),
|
||||
Key: aws.String(key),
|
||||
|
@ -1,6 +1,7 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/go-macaron/session"
|
||||
@ -8,6 +9,7 @@ import (
|
||||
_ "github.com/go-macaron/session/mysql"
|
||||
_ "github.com/go-macaron/session/postgres"
|
||||
_ "github.com/go-macaron/session/redis"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
@ -22,10 +24,12 @@ var sessionManager *session.Manager
|
||||
var sessionOptions *session.Options
|
||||
var startSessionGC func()
|
||||
var getSessionCount func() int
|
||||
var sessionLogger = log.New("session")
|
||||
|
||||
func init() {
|
||||
startSessionGC = func() {
|
||||
sessionManager.GC()
|
||||
sessionLogger.Debug("Session GC")
|
||||
time.AfterFunc(time.Duration(sessionOptions.Gclifetime)*time.Second, startSessionGC)
|
||||
}
|
||||
getSessionCount = func() int {
|
||||
@ -67,7 +71,9 @@ func Sessioner(options *session.Options) macaron.Handler {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go startSessionGC()
|
||||
// start GC threads after some random seconds
|
||||
rndSeconds := 10 + rand.Int63n(180)
|
||||
time.AfterFunc(time.Duration(rndSeconds)*time.Second, startSessionGC)
|
||||
|
||||
return func(ctx *Context) {
|
||||
ctx.Next()
|
||||
|
@ -16,7 +16,7 @@ func init() {
|
||||
alerting.RegisterNotifier(&alerting.NotifierPlugin{
|
||||
Type: "email",
|
||||
Name: "Email",
|
||||
Description: "Sends notifications using Grafana server configured STMP settings",
|
||||
Description: "Sends notifications using Grafana server configured SMTP settings",
|
||||
Factory: NewEmailNotifier,
|
||||
OptionsTemplate: `
|
||||
<h3 class="page-heading">Email addresses</h3>
|
||||
|
@ -126,9 +126,21 @@ func (notifier *ThreemaNotifier) Notify(evalContext *alerting.EvalContext) error
|
||||
data.Set("to", notifier.RecipientID)
|
||||
data.Set("secret", notifier.APISecret)
|
||||
|
||||
// Determine emoji
|
||||
stateEmoji := ""
|
||||
switch evalContext.Rule.State {
|
||||
case m.AlertStateOK:
|
||||
stateEmoji = "\u2705 " // White Heavy Check Mark
|
||||
case m.AlertStateNoData:
|
||||
stateEmoji = "\u2753 " // Black Question Mark Ornament
|
||||
case m.AlertStateAlerting:
|
||||
stateEmoji = "\u26A0 " // Warning sign
|
||||
}
|
||||
|
||||
// Build message
|
||||
message := fmt.Sprintf("%s\n\n*State:* %s\n*Message:* %s\n",
|
||||
evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message)
|
||||
message := fmt.Sprintf("%s%s\n\n*State:* %s\n*Message:* %s\n",
|
||||
stateEmoji, evalContext.GetNotificationTitle(),
|
||||
evalContext.Rule.Name, evalContext.Rule.Message)
|
||||
ruleURL, err := evalContext.GetRuleUrl()
|
||||
if err == nil {
|
||||
message = message + fmt.Sprintf("*URL:* %s\n", ruleURL)
|
||||
|
123
pkg/services/sqlstore/logger.go
Normal file
123
pkg/services/sqlstore/logger.go
Normal file
@ -0,0 +1,123 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
glog "github.com/grafana/grafana/pkg/log"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
type XormLogger struct {
|
||||
grafanaLog glog.Logger
|
||||
level glog.Lvl
|
||||
showSQL bool
|
||||
}
|
||||
|
||||
func NewXormLogger(level glog.Lvl, grafanaLog glog.Logger) *XormLogger {
|
||||
return &XormLogger{
|
||||
grafanaLog: grafanaLog,
|
||||
level: level,
|
||||
showSQL: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Error implement core.ILogger
|
||||
func (s *XormLogger) Err(v ...interface{}) error {
|
||||
if s.level <= glog.LvlError {
|
||||
s.grafanaLog.Error(fmt.Sprint(v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Errorf implement core.ILogger
|
||||
func (s *XormLogger) Errf(format string, v ...interface{}) error {
|
||||
if s.level <= glog.LvlError {
|
||||
s.grafanaLog.Error(fmt.Sprintf(format, v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debug implement core.ILogger
|
||||
func (s *XormLogger) Debug(v ...interface{}) error {
|
||||
if s.level <= glog.LvlDebug {
|
||||
s.grafanaLog.Debug(fmt.Sprint(v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debugf implement core.ILogger
|
||||
func (s *XormLogger) Debugf(format string, v ...interface{}) error {
|
||||
if s.level <= glog.LvlDebug {
|
||||
s.grafanaLog.Debug(fmt.Sprintf(format, v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Info implement core.ILogger
|
||||
func (s *XormLogger) Info(v ...interface{}) error {
|
||||
if s.level <= glog.LvlInfo {
|
||||
s.grafanaLog.Info(fmt.Sprint(v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Infof implement core.ILogger
|
||||
func (s *XormLogger) Infof(format string, v ...interface{}) error {
|
||||
if s.level <= glog.LvlInfo {
|
||||
s.grafanaLog.Info(fmt.Sprintf(format, v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Warn implement core.ILogger
|
||||
func (s *XormLogger) Warning(v ...interface{}) error {
|
||||
if s.level <= glog.LvlWarn {
|
||||
s.grafanaLog.Warn(fmt.Sprint(v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Warnf implement core.ILogger
|
||||
func (s *XormLogger) Warningf(format string, v ...interface{}) error {
|
||||
if s.level <= glog.LvlWarn {
|
||||
s.grafanaLog.Warn(fmt.Sprintf(format, v...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Level implement core.ILogger
|
||||
func (s *XormLogger) Level() core.LogLevel {
|
||||
switch s.level {
|
||||
case glog.LvlError:
|
||||
return core.LOG_ERR
|
||||
case glog.LvlWarn:
|
||||
return core.LOG_WARNING
|
||||
case glog.LvlInfo:
|
||||
return core.LOG_INFO
|
||||
case glog.LvlDebug:
|
||||
return core.LOG_DEBUG
|
||||
default:
|
||||
return core.LOG_ERR
|
||||
}
|
||||
}
|
||||
|
||||
// SetLevel implement core.ILogger
|
||||
func (s *XormLogger) SetLevel(l core.LogLevel) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShowSQL implement core.ILogger
|
||||
func (s *XormLogger) ShowSQL(show ...bool) {
|
||||
s.grafanaLog.Error("ShowSQL", "show", "show")
|
||||
if len(show) == 0 {
|
||||
s.showSQL = true
|
||||
return
|
||||
}
|
||||
s.showSQL = show[0]
|
||||
}
|
||||
|
||||
// IsShowSQL implement core.ILogger
|
||||
func (s *XormLogger) IsShowSQL() bool {
|
||||
return s.showSQL
|
||||
}
|
@ -160,6 +160,9 @@ func getEngine() (*xorm.Engine, error) {
|
||||
engine.SetMaxConns(DbCfg.MaxConn)
|
||||
engine.SetMaxOpenConns(DbCfg.MaxOpenConn)
|
||||
engine.SetMaxIdleConns(DbCfg.MaxIdleConn)
|
||||
// engine.SetLogger(NewXormLogger(log.LvlInfo, log.New("sqlstore.xorm")))
|
||||
// engine.ShowSQL = true
|
||||
// engine.ShowInfo = true
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
@ -190,6 +190,10 @@ func (e *OpenTsdbExecutor) buildMetric(query *tsdb.Query) map[string]interface{}
|
||||
rateOptions["resetValue"] = resetValue.MustFloat64()
|
||||
}
|
||||
|
||||
if !counterMaxCheck && (!resetValueCheck || resetValue.MustFloat64() == 0) {
|
||||
rateOptions["dropcounter"] = true
|
||||
}
|
||||
|
||||
metric["rateOptions"] = rateOptions
|
||||
}
|
||||
|
||||
|
@ -488,6 +488,7 @@ function($, _) {
|
||||
kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L');
|
||||
kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1);
|
||||
kbn.valueFormats.m3 = kbn.formatBuilders.decimalSIPrefix('m3');
|
||||
kbn.valueFormats.dm3 = kbn.formatBuilders.decimalSIPrefix('dm3');
|
||||
kbn.valueFormats.gallons = kbn.formatBuilders.fixedUnit('gal');
|
||||
|
||||
// Flow
|
||||
@ -805,10 +806,11 @@ function($, _) {
|
||||
{
|
||||
text: 'volume',
|
||||
submenu: [
|
||||
{text: 'millilitre', value: 'mlitre' },
|
||||
{text: 'litre', value: 'litre' },
|
||||
{text: 'cubic metre', value: 'm3' },
|
||||
{text: 'gallons', value: 'gallons'},
|
||||
{text: 'millilitre', value: 'mlitre' },
|
||||
{text: 'litre', value: 'litre' },
|
||||
{text: 'cubic metre', value: 'm3' },
|
||||
{text: 'cubic decimetre', value: 'dm3' },
|
||||
{text: 'gallons', value: 'gallons'},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -106,6 +106,7 @@ export class DashNavCtrl {
|
||||
confirmText: confirmText,
|
||||
yesText: 'Delete',
|
||||
onConfirm: function() {
|
||||
$scope.dashboardMeta.canSave = false;
|
||||
$scope.deleteDashboardConfirmed();
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import _ from 'lodash';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import {Variable, assignModelProperties, variableTypes} from './variable';
|
||||
import {Variable, containsVariable, assignModelProperties, variableTypes} from './variable';
|
||||
import {VariableSrv} from './variable_srv';
|
||||
|
||||
export class DatasourceVariable implements Variable {
|
||||
@ -25,7 +25,7 @@ export class DatasourceVariable implements Variable {
|
||||
};
|
||||
|
||||
/** @ngInject **/
|
||||
constructor(private model, private datasourceSrv, private variableSrv) {
|
||||
constructor(private model, private datasourceSrv, private variableSrv, private templateSrv) {
|
||||
assignModelProperties(this, model, this.defaults);
|
||||
this.refresh = 1;
|
||||
}
|
||||
@ -48,7 +48,8 @@ export class DatasourceVariable implements Variable {
|
||||
var regex;
|
||||
|
||||
if (this.regex) {
|
||||
regex = kbn.stringToJsRegex(this.regex);
|
||||
regex = this.templateSrv.replace(this.regex, null, 'regex');
|
||||
regex = kbn.stringToJsRegex(regex);
|
||||
}
|
||||
|
||||
for (var i = 0; i < sources.length; i++) {
|
||||
@ -74,6 +75,9 @@ export class DatasourceVariable implements Variable {
|
||||
}
|
||||
|
||||
dependsOn(variable) {
|
||||
if (this.regex) {
|
||||
return containsVariable(this.regex, variable.name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,9 @@ export class IntervalVariable implements Variable {
|
||||
}
|
||||
|
||||
updateOptions() {
|
||||
// extract options in comma separated string
|
||||
this.options = _.map(this.query.split(/[,]+/), function(text) {
|
||||
// extract options between quotes and/or comma
|
||||
this.options = _.map(this.query.match(/(["'])(.*?)\1|\w+/g), function(text) {
|
||||
text = text.replace(/["']+/g, '');
|
||||
return {text: text.trim(), value: text.trim()};
|
||||
});
|
||||
|
||||
|
@ -124,7 +124,7 @@
|
||||
Step count <tip>How many times should the current time range be divided to calculate the value</tip>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-10" ng-show="current.auto">
|
||||
<select class="gf-form-input" ng-model="current.auto_count" ng-options="f for f in [2,3,4,5,10,20,30,40,50,100,200,300,400,500]" ng-change="runQuery()"></select>
|
||||
<select class="gf-form-input" ng-model="current.auto_count" ng-options="f for f in [1,2,3,4,5,10,20,30,40,50,100,200,300,400,500]" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
|
@ -162,6 +162,9 @@ function (angular, _, queryDef) {
|
||||
};
|
||||
|
||||
$scope.getFieldsInternal = function() {
|
||||
if ($scope.agg.type === 'cardinality') {
|
||||
return $scope.getFields();
|
||||
}
|
||||
return $scope.getFields({$fieldType: 'number'});
|
||||
};
|
||||
|
||||
|
@ -167,7 +167,7 @@ export default class InfluxQuery {
|
||||
var policy = this.target.policy;
|
||||
var measurement = this.target.measurement || 'measurement';
|
||||
|
||||
if (!measurement.match('^/.*/')) {
|
||||
if (!measurement.match('^/.*/$')) {
|
||||
measurement = '"' + measurement+ '"';
|
||||
} else if (interpolate) {
|
||||
measurement = this.templateSrv.replace(measurement, this.scopedVars, 'regex');
|
||||
|
@ -65,7 +65,9 @@ function (angular, _, $) {
|
||||
var el = $(e.currentTarget);
|
||||
var index = getSeriesIndexForElement(el);
|
||||
var seriesInfo = seriesList[index];
|
||||
var scrollPosition = $($container.children('tbody')).scrollTop();
|
||||
ctrl.toggleSeries(seriesInfo, e);
|
||||
$($container.children('tbody')).scrollTop(scrollPosition);
|
||||
}
|
||||
|
||||
function sortLegend(e) {
|
||||
|
@ -7,20 +7,7 @@
|
||||
GOPATH=/go
|
||||
REPO_PATH=$GOPATH/src/github.com/grafana/grafana
|
||||
|
||||
mkdir -p /go/src/github.com/grafana
|
||||
cd /go/src/github.com/grafana
|
||||
|
||||
if [ "$CIRCLE_TAG" != "" ]; then
|
||||
echo "Builing from tag $CIRCLE_TAG"
|
||||
git clone https://github.com/grafana/grafana.git
|
||||
cd $REPO_PATH
|
||||
git checkout $CIRCLE_TAG
|
||||
else
|
||||
echo "Building from branch $CIRCLE_BRANCH"
|
||||
git clone --depth 1 https://github.com/grafana/grafana.git -b $CIRCLE_BRANCH
|
||||
cd $REPO_PATH
|
||||
fi
|
||||
|
||||
cd /go/src/github.com/grafana/grafana
|
||||
echo "current dir: $(pwd)"
|
||||
|
||||
if [ "$CIRCLE_TAG" != "" ]; then
|
||||
@ -47,7 +34,3 @@ else
|
||||
echo "Packaging incremental build for $CIRCLE_BRANCH"
|
||||
go run build.go -buildNumber=${CIRCLE_BUILD_NUM} package latest
|
||||
fi
|
||||
|
||||
cp dist/* /tmp/dist/
|
||||
|
||||
|
||||
|
@ -5,8 +5,10 @@ mkdir -p dist
|
||||
echo "Circle branch: ${CIRCLE_BRANCH}"
|
||||
echo "Circle tag: ${CIRCLE_TAG}"
|
||||
docker run -i -t --name gfbuild \
|
||||
-v $(pwd)/dist:/tmp/dist \
|
||||
-v $(pwd):/go/src/github.com/grafana/grafana \
|
||||
-e "CIRCLE_BRANCH=${CIRCLE_BRANCH}" \
|
||||
-e "CIRCLE_TAG=${CIRCLE_TAG}" \
|
||||
-e "CIRCLE_BUILD_NUM=${CIRCLE_BUILD_NUM}" \
|
||||
grafana/buildcontainer
|
||||
|
||||
sudo chown -R ${USER:=$(/usr/bin/id -run)}:$USER dist
|
||||
|
@ -24,7 +24,8 @@ exit_if_fail test -z "$(gofmt -s -l ./pkg | tee /dev/stderr)"
|
||||
echo "running go vet"
|
||||
exit_if_fail test -z "$(go vet ./pkg/... | tee /dev/stderr)"
|
||||
|
||||
echo "building binaries"
|
||||
exit_if_fail go run build.go build
|
||||
|
||||
echo "running go test"
|
||||
exit_if_fail go test -v ./pkg/...
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user