blob: 0cf2ac24d9553116738c4ae3d388aa711ee98f50 [file] [log] [blame]
// Copyright 2016 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package metric
import (
"context"
"strings"
"time"
"go.chromium.org/luci/common/tsmon"
"go.chromium.org/luci/common/tsmon/distribution"
"go.chromium.org/luci/common/tsmon/field"
"go.chromium.org/luci/common/tsmon/types"
)
// Metrics common to all tasks and devices.
var (
presenceMetric = NewBool(
"presence/up",
"Set to True when the program is running, missing otherwise.",
nil)
)
// Standard metrics for all requests to remote endpoints. These
// metrics should be consistent across all tsmon implementations,
// Python or Go.
var (
requestBytesMetric = NewCumulativeDistribution(
"http/request_bytes",
"Bytes sent per http request (body only).",
&types.MetricMetadata{Units: types.Bytes},
distribution.DefaultBucketer,
field.String("name"), // Usually the requested service name
field.String("client")) // http client used, e.g. urlfetch
responseBytesMetric = NewCumulativeDistribution(
"http/response_bytes",
"Bytes received per http request (content only).",
&types.MetricMetadata{Units: types.Bytes},
distribution.DefaultBucketer,
field.String("name"), // Usually the requested service name
field.String("client")) // http client used, e.g. urlfetch
requestDurationsMetric = NewCumulativeDistribution(
"http/durations",
"Time elapsed between sending a request and getting a response (including parsing) in milliseconds.",
&types.MetricMetadata{Units: types.Milliseconds},
distribution.DefaultBucketer,
field.String("name"), // Usually the requested service name
field.String("client")) // http client used, e.g. urlfetch
responseStatusMetric = NewCounter(
"http/response_status",
"Number of responses received by HTTP status code.",
nil,
field.Int("status"), // HTTP status code
field.String("name"), // Usually the requested service name
field.String("client")) // http client used, e.g. urlfetch
)
// Standard metrics for server-side request handlers. These metrics
// should be consistent across all tsmon implementations, Python or
// Go.
var (
serverRequestBytesMetric = NewCumulativeDistribution(
"http/server_request_bytes",
"Bytes received per http request (body only).",
&types.MetricMetadata{Units: types.Bytes},
distribution.DefaultBucketer,
field.Int("status"), // HTTP status code
field.String("name"), // URL template
field.Bool("is_robot")) // If request is made by a bot
serverResponseBytesMetric = NewCumulativeDistribution(
"http/server_response_bytes",
"Bytes sent per http request (body only).",
&types.MetricMetadata{Units: types.Bytes},
distribution.DefaultBucketer,
field.Int("status"), // HTTP status code
field.String("name"), // URL template
field.Bool("is_robot")) // If request is made by a bot
serverDurationsMetric = NewCumulativeDistribution(
"http/server_durations",
"Time elapsed between receiving a request and sending a response (including parsing) in milliseconds.",
&types.MetricMetadata{Units: types.Milliseconds},
distribution.DefaultBucketer,
field.Int("status"), // HTTP status code
field.String("name"), // URL template
field.Bool("is_robot")) // If request is made by a bot
serverResponseStatusMetric = NewCounter(
"http/server_response_status",
"Number of responses sent by HTTP status code.",
nil,
field.Int("status"), // HTTP status code
field.String("name"), // URL template
field.Bool("is_robot")) // If request is made by a bot
)
func init() {
registerCallbacks(context.Background())
}
func registerCallbacks(ctx context.Context) {
tsmon.RegisterCallbackIn(ctx, func(ctx context.Context) {
presenceMetric.Set(ctx, true)
})
}
// UpdateHTTPMetrics updates the metrics for a request to a remote server.
func UpdateHTTPMetrics(ctx context.Context, name string, client string,
code int, duration time.Duration, requestBytes int64, responseBytes int64) {
requestBytesMetric.Add(ctx, float64(requestBytes), name, client)
responseBytesMetric.Add(ctx, float64(responseBytes), name, client)
requestDurationsMetric.Add(ctx, float64(int64(duration)/int64(time.Millisecond)), name, client)
responseStatusMetric.Add(ctx, 1, code, name, client)
}
// UpdateServerMetrics updates the metrics for a handled request.
func UpdateServerMetrics(ctx context.Context, name string, code int,
duration time.Duration, requestBytes int64, responseBytes int64,
userAgent string) {
isRobot := (strings.Contains(userAgent, "GoogleBot") ||
strings.Contains(userAgent, "GoogleSecurityScanner") ||
strings.HasPrefix(userAgent, "kube-probe/") ||
strings.HasPrefix(userAgent, "GoogleHC/") ||
userAgent == "B3M/prober")
serverDurationsMetric.Add(ctx, float64(int64(duration)/int64(time.Millisecond)), code, name, isRobot)
serverResponseStatusMetric.Add(ctx, 1, code, name, isRobot)
serverRequestBytesMetric.Add(ctx, float64(requestBytes), code, name, isRobot)
serverResponseBytesMetric.Add(ctx, float64(responseBytes), code, name, isRobot)
}