Skip to content

Commit

Permalink
[extension/healthcheckv2] Add partial gRPC service implementation (#3…
Browse files Browse the repository at this point in the history
…4028)

**Description:** <Describe what has changed.>
The PR is the fourth in a series to decompose #30673 into more
manageable pieces for review. This PR introduces the basic structure for
the gRPC health check service, which is an implementation of the
[grpc_health_v1
service](https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto).
This PR implements the unary `Check` RPC. In order minimize PR size, the
streaming `Watch` RPC will be introduced in a followup.

**Link to tracking Issue:** #26661

**Testing:** Units / manual

**Documentation:** Comments, etc.
  • Loading branch information
mwear authored Jul 11, 2024
1 parent 42c03a2 commit 16a7b29
Show file tree
Hide file tree
Showing 6 changed files with 928 additions and 1 deletion.
27 changes: 27 additions & 0 deletions .chloggen/healthcheckv2-grpc-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: 'enhancement'

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: 'healthcheckv2extension'

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add partial gRPC service implementation to healthcheckv2.

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [26661]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
2 changes: 1 addition & 1 deletion extension/healthcheckv2extension/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
go.opentelemetry.io/otel/trace v1.28.0
go.uber.org/goleak v1.3.0
go.uber.org/zap v1.27.0
google.golang.org/grpc v1.65.0
)

require (
Expand Down Expand Up @@ -66,7 +67,6 @@ require (
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Expand Down
61 changes: 61 additions & 0 deletions extension/healthcheckv2extension/internal/grpc/grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package grpc // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckv2extension/internal/grpc"

import (
"context"
"time"

"go.opentelemetry.io/collector/component"
"google.golang.org/grpc/codes"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
grpcstatus "google.golang.org/grpc/status"

"github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckv2extension/internal/status"
)

var (
errNotFound = grpcstatus.Error(codes.NotFound, "Service not found.")

statusToServingStatusMap = map[component.Status]healthpb.HealthCheckResponse_ServingStatus{
component.StatusNone: healthpb.HealthCheckResponse_NOT_SERVING,
component.StatusStarting: healthpb.HealthCheckResponse_NOT_SERVING,
component.StatusOK: healthpb.HealthCheckResponse_SERVING,
component.StatusRecoverableError: healthpb.HealthCheckResponse_SERVING,
component.StatusPermanentError: healthpb.HealthCheckResponse_SERVING,
component.StatusFatalError: healthpb.HealthCheckResponse_NOT_SERVING,
component.StatusStopping: healthpb.HealthCheckResponse_NOT_SERVING,
component.StatusStopped: healthpb.HealthCheckResponse_NOT_SERVING,
}
)

func (s *Server) Check(
_ context.Context,
req *healthpb.HealthCheckRequest,
) (*healthpb.HealthCheckResponse, error) {
st, ok := s.aggregator.AggregateStatus(status.Scope(req.Service), status.Concise)
if !ok {
return nil, errNotFound
}

return &healthpb.HealthCheckResponse{
Status: s.toServingStatus(st.Event),
}, nil
}

func (s *Server) toServingStatus(
ev status.Event,
) healthpb.HealthCheckResponse_ServingStatus {
if s.componentHealthConfig.IncludeRecoverable &&
ev.Status() == component.StatusRecoverableError &&
time.Now().After(ev.Timestamp().Add(s.componentHealthConfig.RecoveryDuration)) {
return healthpb.HealthCheckResponse_NOT_SERVING
}

if s.componentHealthConfig.IncludePermanent && ev.Status() == component.StatusPermanentError {
return healthpb.HealthCheckResponse_NOT_SERVING
}

return statusToServingStatusMap[ev.Status()]
}
Loading

0 comments on commit 16a7b29

Please sign in to comment.