Merge branch 'alerting' into grafana-annotations
This commit is contained in:
@@ -67,25 +67,29 @@ func init() {
|
||||
"CoreNodesRunning", "CoreNodesPending", "LiveDataNodes", "MRTotalNodes", "MRActiveNodes", "MRLostNodes", "MRUnhealthyNodes", "MRDecommissionedNodes", "MRRebootedNodes",
|
||||
"S3BytesWritten", "S3BytesRead", "HDFSUtilization", "HDFSBytesRead", "HDFSBytesWritten", "MissingBlocks", "CorruptBlocks", "TotalLoad", "MemoryTotalMB", "MemoryReservedMB", "MemoryAvailableMB", "MemoryAllocatedMB", "PendingDeletionBlocks", "UnderReplicatedBlocks", "DfsPendingReplicationBlocks", "CapacityRemainingGB",
|
||||
"HbaseBackupFailed", "MostRecentBackupDuration", "TimeSinceLastSuccessfulBackup"},
|
||||
"AWS/ES": {"ClusterStatus.green", "ClusterStatus.yellow", "ClusterStatus.red", "Nodes", "SearchableDocuments", "DeletedDocuments", "CPUUtilization", "FreeStorageSpace", "JVMMemoryPressure", "AutomatedSnapshotFailure", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "DiskQueueLength", "ReadIOPS", "WriteIOPS"},
|
||||
"AWS/Events": {"Invocations", "FailedInvocations", "TriggeredRules", "MatchedEvents", "ThrottledRules"},
|
||||
"AWS/Kinesis": {"GetRecords.Bytes", "GetRecords.IteratorAge", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Records", "GetRecords.Success", "IncomingBytes", "IncomingRecords", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "ReadProvisionedThroughputExceeded", "WriteProvisionedThroughputExceeded", "IteratorAgeMilliseconds", "OutgoingBytes", "OutgoingRecords"},
|
||||
"AWS/Lambda": {"Invocations", "Errors", "Duration", "Throttles"},
|
||||
"AWS/Logs": {"IncomingBytes", "IncomingLogEvents", "ForwardedBytes", "ForwardedLogEvents", "DeliveryErrors", "DeliveryThrottling"},
|
||||
"AWS/ML": {"PredictCount", "PredictFailureCount"},
|
||||
"AWS/OpsWorks": {"cpu_idle", "cpu_nice", "cpu_system", "cpu_user", "cpu_waitio", "load_1", "load_5", "load_15", "memory_buffers", "memory_cached", "memory_free", "memory_swap", "memory_total", "memory_used", "procs"},
|
||||
"AWS/Redshift": {"CPUUtilization", "DatabaseConnections", "HealthStatus", "MaintenanceMode", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "PercentageDiskSpaceUsed", "ReadIOPS", "ReadLatency", "ReadThroughput", "WriteIOPS", "WriteLatency", "WriteThroughput"},
|
||||
"AWS/RDS": {"BinLogDiskUsage", "CPUUtilization", "CPUCreditUsage", "CPUCreditBalance", "DatabaseConnections", "DiskQueueDepth", "FreeableMemory", "FreeStorageSpace", "ReplicaLag", "SwapUsage", "ReadIOPS", "WriteIOPS", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "NetworkReceiveThroughput", "NetworkTransmitThroughput"},
|
||||
"AWS/Route53": {"HealthCheckStatus", "HealthCheckPercentageHealthy", "ConnectionTime", "SSLHandshakeTime", "TimeToFirstByte"},
|
||||
"AWS/S3": {"BucketSizeBytes", "NumberOfObjects"},
|
||||
"AWS/SNS": {"NumberOfMessagesPublished", "PublishSize", "NumberOfNotificationsDelivered", "NumberOfNotificationsFailed"},
|
||||
"AWS/SQS": {"NumberOfMessagesSent", "SentMessageSize", "NumberOfMessagesReceived", "NumberOfEmptyReceives", "NumberOfMessagesDeleted", "ApproximateNumberOfMessagesDelayed", "ApproximateNumberOfMessagesVisible", "ApproximateNumberOfMessagesNotVisible"},
|
||||
"AWS/ES": {"ClusterStatus.green", "ClusterStatus.yellow", "ClusterStatus.red", "Nodes", "SearchableDocuments", "DeletedDocuments", "CPUUtilization", "FreeStorageSpace", "JVMMemoryPressure", "AutomatedSnapshotFailure", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "DiskQueueLength", "ReadIOPS", "WriteIOPS"},
|
||||
"AWS/Events": {"Invocations", "FailedInvocations", "TriggeredRules", "MatchedEvents", "ThrottledRules"},
|
||||
"AWS/Firehose": {"DeliveryToElasticsearch.Bytes", "DeliveryToElasticsearch.Records", "DeliveryToElasticsearch.Success", "DeliveryToRedshift.Bytes", "DeliveryToRedshift.Records", "DeliveryToRedshift.Success", "DeliveryToS3.Bytes", "DeliveryToS3.DataFreshness", "DeliveryToS3.Records", "DeliveryToS3.Success", "IncomingBytes", "IncomingRecords", "DescribeDeliveryStream.Latency", "DescribeDeliveryStream.Requests", "ListDeliveryStreams.Latency", "ListDeliveryStreams.Requests", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Requests", "PutRecordBatch.Bytes", "PutRecordBatch.Latency", "PutRecordBatch.Records", "PutRecordBatch.Requests", "UpdateDeliveryStream.Latency", "UpdateDeliveryStream.Requests"},
|
||||
"AWS/IoT": {"PublishIn.Success", "PublishOut.Success", "Subscribe.Success", "Ping.Success", "Connect.Success", "GetThingShadow.Accepted"},
|
||||
"AWS/Kinesis": {"GetRecords.Bytes", "GetRecords.IteratorAge", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Records", "GetRecords.Success", "IncomingBytes", "IncomingRecords", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "ReadProvisionedThroughputExceeded", "WriteProvisionedThroughputExceeded", "IteratorAgeMilliseconds", "OutgoingBytes", "OutgoingRecords"},
|
||||
"AWS/KinesisAnalytics": {"Bytes", "MillisBehindLatest", "Records", "Success"},
|
||||
"AWS/Lambda": {"Invocations", "Errors", "Duration", "Throttles"},
|
||||
"AWS/Logs": {"IncomingBytes", "IncomingLogEvents", "ForwardedBytes", "ForwardedLogEvents", "DeliveryErrors", "DeliveryThrottling"},
|
||||
"AWS/ML": {"PredictCount", "PredictFailureCount"},
|
||||
"AWS/OpsWorks": {"cpu_idle", "cpu_nice", "cpu_system", "cpu_user", "cpu_waitio", "load_1", "load_5", "load_15", "memory_buffers", "memory_cached", "memory_free", "memory_swap", "memory_total", "memory_used", "procs"},
|
||||
"AWS/Redshift": {"CPUUtilization", "DatabaseConnections", "HealthStatus", "MaintenanceMode", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "PercentageDiskSpaceUsed", "ReadIOPS", "ReadLatency", "ReadThroughput", "WriteIOPS", "WriteLatency", "WriteThroughput"},
|
||||
"AWS/RDS": {"BinLogDiskUsage", "CPUUtilization", "CPUCreditUsage", "CPUCreditBalance", "DatabaseConnections", "DiskQueueDepth", "FreeableMemory", "FreeStorageSpace", "ReplicaLag", "SwapUsage", "ReadIOPS", "WriteIOPS", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "NetworkReceiveThroughput", "NetworkTransmitThroughput"},
|
||||
"AWS/Route53": {"HealthCheckStatus", "HealthCheckPercentageHealthy", "ConnectionTime", "SSLHandshakeTime", "TimeToFirstByte"},
|
||||
"AWS/S3": {"BucketSizeBytes", "NumberOfObjects"},
|
||||
"AWS/SNS": {"NumberOfMessagesPublished", "PublishSize", "NumberOfNotificationsDelivered", "NumberOfNotificationsFailed"},
|
||||
"AWS/SQS": {"NumberOfMessagesSent", "SentMessageSize", "NumberOfMessagesReceived", "NumberOfEmptyReceives", "NumberOfMessagesDeleted", "ApproximateNumberOfMessagesDelayed", "ApproximateNumberOfMessagesVisible", "ApproximateNumberOfMessagesNotVisible"},
|
||||
"AWS/StorageGateway": {"CacheHitPercent", "CachePercentUsed", "CachePercentDirty", "CloudBytesDownloaded", "CloudDownloadLatency", "CloudBytesUploaded", "UploadBufferFree", "UploadBufferPercentUsed", "UploadBufferUsed", "QueuedWrites", "ReadBytes", "ReadTime", "TotalCacheSize", "WriteBytes", "WriteTime", "TimeSinceLastRecoveryPoint", "WorkingStorageFree", "WorkingStoragePercentUsed", "WorkingStorageUsed",
|
||||
"CacheHitPercent", "CachePercentUsed", "CachePercentDirty", "ReadBytes", "ReadTime", "WriteBytes", "WriteTime", "QueuedWrites"},
|
||||
"AWS/SWF": {"DecisionTaskScheduleToStartTime", "DecisionTaskStartToCloseTime", "DecisionTasksCompleted", "StartedDecisionTasksTimedOutOnClose", "WorkflowStartToCloseTime", "WorkflowsCanceled", "WorkflowsCompleted", "WorkflowsContinuedAsNew", "WorkflowsFailed", "WorkflowsTerminated", "WorkflowsTimedOut",
|
||||
"ActivityTaskScheduleToCloseTime", "ActivityTaskScheduleToStartTime", "ActivityTaskStartToCloseTime", "ActivityTasksCanceled", "ActivityTasksCompleted", "ActivityTasksFailed", "ScheduledActivityTasksTimedOutOnClose", "ScheduledActivityTasksTimedOutOnStart", "StartedActivityTasksTimedOutOnClose", "StartedActivityTasksTimedOutOnHeartbeat"},
|
||||
"AWS/WAF": {"AllowedRequests", "BlockedRequests", "CountedRequests"},
|
||||
"AWS/WorkSpaces": {"Available", "Unhealthy", "ConnectionAttempt", "ConnectionSuccess", "ConnectionFailure", "SessionLaunchTime", "InSessionLatency", "SessionDisconnect"},
|
||||
"KMS": {"SecondsUntilKeyMaterialExpiration"},
|
||||
}
|
||||
dimensionsMap = map[string][]string{
|
||||
"AWS/ApiGateway": {"ApiName", "Method", "Resource", "Stage"},
|
||||
@@ -106,7 +110,10 @@ func init() {
|
||||
"AWS/ElasticMapReduce": {"ClusterId", "JobFlowId", "JobId"},
|
||||
"AWS/ES": {"ClientId", "DomainName"},
|
||||
"AWS/Events": {"RuleName"},
|
||||
"AWS/Firehose": {},
|
||||
"AWS/IoT": {"Protocol"},
|
||||
"AWS/Kinesis": {"StreamName", "ShardID"},
|
||||
"AWS/KinesisAnalytics": {"Flow", "Id", "Application"},
|
||||
"AWS/Lambda": {"FunctionName", "Resource", "Version", "Alias"},
|
||||
"AWS/Logs": {"LogGroupName", "DestinationType", "FilterName"},
|
||||
"AWS/ML": {"MLModelId", "RequestMode"},
|
||||
@@ -121,6 +128,7 @@ func init() {
|
||||
"AWS/SWF": {"Domain", "WorkflowTypeName", "WorkflowTypeVersion", "ActivityTypeName", "ActivityTypeVersion"},
|
||||
"AWS/WAF": {"Rule", "WebACL"},
|
||||
"AWS/WorkSpaces": {"DirectoryId", "WorkspaceId"},
|
||||
"KMS": {"KeyId"},
|
||||
}
|
||||
|
||||
customMetricsMetricsMap = make(map[string]map[string]map[string]*CustomMetricsCache)
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"gopkg.in/macaron.v1"
|
||||
@@ -88,10 +87,8 @@ func ApiError(status int, message string, err error) *NormalResponse {
|
||||
|
||||
switch status {
|
||||
case 404:
|
||||
metrics.M_Api_Status_404.Inc(1)
|
||||
data["message"] = "Not Found"
|
||||
case 500:
|
||||
metrics.M_Api_Status_500.Inc(1)
|
||||
data["message"] = "Internal Server Error"
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ func newMacaron() *macaron.Macaron {
|
||||
|
||||
m.Use(middleware.GetContextHandler())
|
||||
m.Use(middleware.Sessioner(&setting.SessionOptions))
|
||||
m.Use(middleware.RequestMetrics())
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
+10
-1
@@ -48,7 +48,16 @@ func (a *ldapAuther) Dial() error {
|
||||
ServerName: host,
|
||||
RootCAs: certPool,
|
||||
}
|
||||
a.conn, err = ldap.DialTLS("tcp", address, tlsCfg)
|
||||
if a.server.StartTLS {
|
||||
a.conn, err = ldap.Dial("tcp", address)
|
||||
if err == nil {
|
||||
if err = a.conn.StartTLS(tlsCfg); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
a.conn, err = ldap.DialTLS("tcp", address, tlsCfg)
|
||||
}
|
||||
} else {
|
||||
a.conn, err = ldap.Dial("tcp", address)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ type LdapServerConf struct {
|
||||
Host string `toml:"host"`
|
||||
Port int `toml:"port"`
|
||||
UseSSL bool `toml:"use_ssl"`
|
||||
StartTLS bool `toml:"start_tls"`
|
||||
SkipVerifySSL bool `toml:"ssl_skip_verify"`
|
||||
RootCACert string `toml:"root_ca_cert"`
|
||||
BindDN string `toml:"bind_dn"`
|
||||
|
||||
+17
-2
@@ -13,8 +13,15 @@ var (
|
||||
M_Page_Status_200 Counter
|
||||
M_Page_Status_500 Counter
|
||||
M_Page_Status_404 Counter
|
||||
M_Api_Status_500 Counter
|
||||
M_Page_Status_Unknown Counter
|
||||
M_Api_Status_200 Counter
|
||||
M_Api_Status_404 Counter
|
||||
M_Api_Status_500 Counter
|
||||
M_Api_Status_Unknown Counter
|
||||
M_Proxy_Status_200 Counter
|
||||
M_Proxy_Status_404 Counter
|
||||
M_Proxy_Status_500 Counter
|
||||
M_Proxy_Status_Unknown Counter
|
||||
M_Api_User_SignUpStarted Counter
|
||||
M_Api_User_SignUpCompleted Counter
|
||||
M_Api_User_SignUpInvite Counter
|
||||
@@ -54,9 +61,17 @@ func initMetricVars(settings *MetricSettings) {
|
||||
M_Page_Status_200 = RegCounter("page.resp_status", "code", "200")
|
||||
M_Page_Status_500 = RegCounter("page.resp_status", "code", "500")
|
||||
M_Page_Status_404 = RegCounter("page.resp_status", "code", "404")
|
||||
M_Page_Status_Unknown = RegCounter("page.resp_status", "code", "unknown")
|
||||
|
||||
M_Api_Status_500 = RegCounter("api.resp_status", "code", "500")
|
||||
M_Api_Status_200 = RegCounter("api.resp_status", "code", "200")
|
||||
M_Api_Status_404 = RegCounter("api.resp_status", "code", "404")
|
||||
M_Api_Status_500 = RegCounter("api.resp_status", "code", "500")
|
||||
M_Api_Status_Unknown = RegCounter("api.resp_status", "code", "unknown")
|
||||
|
||||
M_Proxy_Status_200 = RegCounter("proxy.resp_status", "code", "200")
|
||||
M_Proxy_Status_404 = RegCounter("proxy.resp_status", "code", "404")
|
||||
M_Proxy_Status_500 = RegCounter("proxy.resp_status", "code", "500")
|
||||
M_Proxy_Status_Unknown = RegCounter("proxy.resp_status", "code", "unknown")
|
||||
|
||||
M_Api_User_SignUpStarted = RegCounter("api.user.signup_started")
|
||||
M_Api_User_SignUpCompleted = RegCounter("api.user.signup_completed")
|
||||
|
||||
@@ -49,9 +49,9 @@ func Logger() macaron.Handler {
|
||||
if ctx, ok := c.Data["ctx"]; ok {
|
||||
ctxTyped := ctx.(*Context)
|
||||
if status == 500 {
|
||||
ctxTyped.Logger.Error("Request Completed", "method", req.Method, "path", req.URL.Path, "status", status, "remote_addr", c.RemoteAddr(), "time_ns", timeTakenMs, "size", rw.Size())
|
||||
ctxTyped.Logger.Error("Request Completed", "method", req.Method, "path", req.URL.Path, "status", status, "remote_addr", c.RemoteAddr(), "time_ms", timeTakenMs, "size", rw.Size())
|
||||
} else {
|
||||
ctxTyped.Logger.Info("Request Completed", "method", req.Method, "path", req.URL.Path, "status", status, "remote_addr", c.RemoteAddr(), "time_ns", timeTakenMs, "size", rw.Size())
|
||||
ctxTyped.Logger.Info("Request Completed", "method", req.Method, "path", req.URL.Path, "status", status, "remote_addr", c.RemoteAddr(), "time_ms", timeTakenMs, "size", rw.Size())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,15 +208,6 @@ func (ctx *Context) Handle(status int, title string, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
switch status {
|
||||
case 200:
|
||||
metrics.M_Page_Status_200.Inc(1)
|
||||
case 404:
|
||||
metrics.M_Page_Status_404.Inc(1)
|
||||
case 500:
|
||||
metrics.M_Page_Status_500.Inc(1)
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = title
|
||||
ctx.HTML(status, strconv.Itoa(status))
|
||||
}
|
||||
@@ -243,10 +234,8 @@ func (ctx *Context) JsonApiErr(status int, message string, err error) {
|
||||
|
||||
switch status {
|
||||
case 404:
|
||||
metrics.M_Api_Status_404.Inc(1)
|
||||
resp["message"] = "Not Found"
|
||||
case 500:
|
||||
metrics.M_Api_Status_500.Inc(1)
|
||||
resp["message"] = "Internal Server Error"
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
func RequestMetrics() macaron.Handler {
|
||||
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
|
||||
rw := res.(macaron.ResponseWriter)
|
||||
c.Next()
|
||||
|
||||
status := rw.Status()
|
||||
|
||||
if strings.HasPrefix(req.RequestURI, "/api/datasources/proxy") {
|
||||
countProxyRequests(status)
|
||||
} else if strings.HasPrefix(req.RequestURI, "/api/") {
|
||||
countApiRequests(status)
|
||||
} else {
|
||||
countPageRequests(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func countApiRequests(status int) {
|
||||
switch status {
|
||||
case 200:
|
||||
metrics.M_Api_Status_200.Inc(1)
|
||||
case 404:
|
||||
metrics.M_Api_Status_404.Inc(1)
|
||||
case 500:
|
||||
metrics.M_Api_Status_500.Inc(1)
|
||||
default:
|
||||
metrics.M_Api_Status_Unknown.Inc(1)
|
||||
}
|
||||
}
|
||||
|
||||
func countPageRequests(status int) {
|
||||
switch status {
|
||||
case 200:
|
||||
metrics.M_Page_Status_200.Inc(1)
|
||||
case 404:
|
||||
metrics.M_Page_Status_404.Inc(1)
|
||||
case 500:
|
||||
metrics.M_Page_Status_500.Inc(1)
|
||||
default:
|
||||
metrics.M_Page_Status_Unknown.Inc(1)
|
||||
}
|
||||
}
|
||||
|
||||
func countProxyRequests(status int) {
|
||||
switch status {
|
||||
case 200:
|
||||
metrics.M_Proxy_Status_200.Inc(1)
|
||||
case 404:
|
||||
metrics.M_Proxy_Status_404.Inc(1)
|
||||
case 500:
|
||||
metrics.M_Proxy_Status_500.Inc(1)
|
||||
default:
|
||||
metrics.M_Proxy_Status_Unknown.Inc(1)
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package models
|
||||
|
||||
// type AlertState struct {
|
||||
// Id int64 `json:"-"`
|
||||
// OrgId int64 `json:"-"`
|
||||
// AlertId int64 `json:"alertId"`
|
||||
// State string `json:"state"`
|
||||
// Created time.Time `json:"created"`
|
||||
// Info string `json:"info"`
|
||||
// TriggeredAlerts *simplejson.Json `json:"triggeredAlerts"`
|
||||
// }
|
||||
//
|
||||
// func (this *UpdateAlertStateCommand) IsValidState() bool {
|
||||
// for _, v := range alertstates.ValidStates {
|
||||
// if this.State == v {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// // Commands
|
||||
//
|
||||
// type UpdateAlertStateCommand struct {
|
||||
// AlertId int64 `json:"alertId" binding:"Required"`
|
||||
// OrgId int64 `json:"orgId" binding:"Required"`
|
||||
// State string `json:"state" binding:"Required"`
|
||||
// Info string `json:"info"`
|
||||
//
|
||||
// Result *Alert
|
||||
// }
|
||||
//
|
||||
// // Queries
|
||||
//
|
||||
// type GetAlertsStateQuery struct {
|
||||
// OrgId int64 `json:"orgId" binding:"Required"`
|
||||
// AlertId int64 `json:"alertId" binding:"Required"`
|
||||
//
|
||||
// Result *[]AlertState
|
||||
// }
|
||||
//
|
||||
// type GetLastAlertStateQuery struct {
|
||||
// AlertId int64
|
||||
// OrgId int64
|
||||
//
|
||||
// Result *AlertState
|
||||
// }
|
||||
@@ -1 +0,0 @@
|
||||
package conditions
|
||||
@@ -38,6 +38,7 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) {
|
||||
return
|
||||
}
|
||||
|
||||
emptySerieCount := 0
|
||||
for _, series := range seriesList {
|
||||
reducedValue := c.Reducer.Reduce(series)
|
||||
evalMatch := c.Evaluator.Eval(reducedValue)
|
||||
@@ -55,13 +56,14 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) {
|
||||
})
|
||||
}
|
||||
|
||||
context.Firing = evalMatch
|
||||
|
||||
// handle no data scenario
|
||||
if reducedValue == nil {
|
||||
context.NoDataFound = true
|
||||
emptySerieCount++
|
||||
}
|
||||
}
|
||||
|
||||
context.NoDataFound = emptySerieCount == len(seriesList)
|
||||
context.Firing = len(context.EvalMatches) > 0
|
||||
}
|
||||
|
||||
func (c *QueryCondition) executeQuery(context *alerting.EvalContext) (tsdb.TimeSeriesSlice, error) {
|
||||
|
||||
@@ -59,6 +59,45 @@ func TestQueryCondition(t *testing.T) {
|
||||
So(ctx.result.Error, ShouldBeNil)
|
||||
So(ctx.result.Firing, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Should fire if only first serie matches", func() {
|
||||
one := float64(120)
|
||||
two := float64(0)
|
||||
ctx.series = tsdb.TimeSeriesSlice{
|
||||
tsdb.NewTimeSeries("test1", [][2]*float64{{&one, &two}}),
|
||||
tsdb.NewTimeSeries("test2", [][2]*float64{{&two, &two}}),
|
||||
}
|
||||
ctx.exec()
|
||||
|
||||
So(ctx.result.Error, ShouldBeNil)
|
||||
So(ctx.result.Firing, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Empty series", func() {
|
||||
Convey("Should set NoDataFound both series are empty", func() {
|
||||
ctx.series = tsdb.TimeSeriesSlice{
|
||||
tsdb.NewTimeSeries("test1", [][2]*float64{}),
|
||||
tsdb.NewTimeSeries("test2", [][2]*float64{}),
|
||||
}
|
||||
ctx.exec()
|
||||
|
||||
So(ctx.result.Error, ShouldBeNil)
|
||||
So(ctx.result.NoDataFound, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Should not set NoDataFound if one serie is empty", func() {
|
||||
one := float64(120)
|
||||
two := float64(0)
|
||||
ctx.series = tsdb.TimeSeriesSlice{
|
||||
tsdb.NewTimeSeries("test1", [][2]*float64{}),
|
||||
tsdb.NewTimeSeries("test2", [][2]*float64{{&one, &two}}),
|
||||
}
|
||||
ctx.exec()
|
||||
|
||||
So(ctx.result.Error, ShouldBeNil)
|
||||
So(ctx.result.NoDataFound, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type DefaultEvalHandler struct {
|
||||
func NewEvalHandler() *DefaultEvalHandler {
|
||||
return &DefaultEvalHandler{
|
||||
log: log.New("alerting.evalHandler"),
|
||||
alertJobTimeout: time.Second * 5,
|
||||
alertJobTimeout: time.Second * 10,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ func (e *DefaultEvalHandler) Eval(context *EvalContext) {
|
||||
|
||||
select {
|
||||
case <-time.After(e.alertJobTimeout):
|
||||
context.Error = fmt.Errorf("Timeout")
|
||||
context.Error = fmt.Errorf("Execution timed out after %v", e.alertJobTimeout)
|
||||
context.EndTime = time.Now()
|
||||
e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id)
|
||||
e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id, "timeout setting", e.alertJobTimeout)
|
||||
e.retry(context)
|
||||
case <-context.DoneChan:
|
||||
e.log.Debug("Job Execution done", "timeMs", context.GetDurationMs(), "alertId", context.Rule.Id, "firing", context.Firing)
|
||||
@@ -45,10 +45,10 @@ func (e *DefaultEvalHandler) Eval(context *EvalContext) {
|
||||
func (e *DefaultEvalHandler) retry(context *EvalContext) {
|
||||
e.log.Debug("Retrying eval exeuction", "alertId", context.Rule.Id)
|
||||
|
||||
context.RetryCount++
|
||||
if context.RetryCount > MaxRetries {
|
||||
if context.RetryCount < MaxRetries {
|
||||
context.DoneChan = make(chan bool, 1)
|
||||
context.CancelChan = make(chan bool, 1)
|
||||
context.RetryCount++
|
||||
e.Eval(context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func GetDataSourceByName(query *m.GetDataSourceByNameQuery) error {
|
||||
}
|
||||
|
||||
func GetDataSources(query *m.GetDataSourcesQuery) error {
|
||||
sess := x.Limit(100, 0).Where("org_id=?", query.OrgId).Asc("name")
|
||||
sess := x.Limit(1000, 0).Where("org_id=?", query.OrgId).Asc("name")
|
||||
|
||||
query.Result = make([]*m.DataSource, 0)
|
||||
return sess.Find(&query.Result)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package graphite
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -15,10 +16,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
var (
|
||||
HttpClient = http.Client{Timeout: time.Duration(10 * time.Second)}
|
||||
)
|
||||
|
||||
type GraphiteExecutor struct {
|
||||
*tsdb.DataSourceInfo
|
||||
}
|
||||
@@ -27,11 +24,23 @@ func NewGraphiteExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor {
|
||||
return &GraphiteExecutor{dsInfo}
|
||||
}
|
||||
|
||||
var glog log.Logger
|
||||
var (
|
||||
glog log.Logger
|
||||
HttpClient http.Client
|
||||
)
|
||||
|
||||
func init() {
|
||||
glog = log.New("tsdb.graphite")
|
||||
tsdb.RegisterExecutor("graphite", NewGraphiteExecutor)
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
HttpClient = http.Client{
|
||||
Timeout: time.Duration(10 * time.Second),
|
||||
Transport: tr,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryContext) *tsdb.BatchResult {
|
||||
|
||||
Reference in New Issue
Block a user