| // 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) |
| } |