From 6d32c09daf9f91ec0dc35c45732e168663dfda10 Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:55:31 -0600 Subject: [PATCH] [component] Move component status reporting public API to new componentstatus module (#10730) #### Description Duplicates component status reporting features from `component` into a separate module, `componentstatus`. In a future PR, when `component.TelemetrySettings.ReportStatus` is removed, I'll update Core to depend on `componentstatus`. This work isolates component status public API from `component` and `extensions`, which will allow us to move forward with their 1.0 work while component status reporting matures. #### Link to tracking issue Related to https://github.com/open-telemetry/opentelemetry-collector/pull/10725 --------- Co-authored-by: Matthew Wear --- .chloggen/componentstatus-new-module.yaml | 25 ++++ Makefile | 2 + component/componentstatus/Makefile | 1 + component/componentstatus/go.mod | 34 ++++++ component/componentstatus/go.sum | 78 ++++++++++++ component/componentstatus/instance.go | 16 +++ component/componentstatus/status.go | 139 ++++++++++++++++++++++ component/componentstatus/status_test.go | 90 ++++++++++++++ versions.yaml | 1 + 9 files changed, 386 insertions(+) create mode 100644 .chloggen/componentstatus-new-module.yaml create mode 100644 component/componentstatus/Makefile create mode 100644 component/componentstatus/go.mod create mode 100644 component/componentstatus/go.sum create mode 100644 component/componentstatus/instance.go create mode 100644 component/componentstatus/status.go create mode 100644 component/componentstatus/status_test.go diff --git a/.chloggen/componentstatus-new-module.yaml b/.chloggen/componentstatus-new-module.yaml new file mode 100644 index 00000000000..17a11840b58 --- /dev/null +++ b/.chloggen/componentstatus-new-module.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: new_component + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: componentstatus + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Adds new componentstatus module that will soon replace status content in component. + +# One or more tracking issues or pull requests related to the change +issues: [10730] + +# (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: + +# 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: [api] diff --git a/Makefile b/Makefile index e66d2fd36fd..ba35b2e397e 100644 --- a/Makefile +++ b/Makefile @@ -259,6 +259,7 @@ check-contrib: -replace go.opentelemetry.io/collector=$(CURDIR) \ -replace go.opentelemetry.io/collector/client=$(CURDIR)/client \ -replace go.opentelemetry.io/collector/component=$(CURDIR)/component \ + -replace go.opentelemetry.io/collector/component/componentstatus=$(CURDIR)/component/componentstatus \ -replace go.opentelemetry.io/collector/config/configauth=$(CURDIR)/config/configauth \ -replace go.opentelemetry.io/collector/config/configcompression=$(CURDIR)/config/configcompression \ -replace go.opentelemetry.io/collector/config/configgrpc=$(CURDIR)/config/configgrpc \ @@ -321,6 +322,7 @@ restore-contrib: -dropreplace go.opentelemetry.io/collector \ -dropreplace go.opentelemetry.io/collector/client \ -dropreplace go.opentelemetry.io/collector/component \ + -dropreplace go.opentelemetry.io/collector/component/componentstatus \ -dropreplace go.opentelemetry.io/collector/config/configauth \ -dropreplace go.opentelemetry.io/collector/config/configcompression \ -dropreplace go.opentelemetry.io/collector/config/configgrpc \ diff --git a/component/componentstatus/Makefile b/component/componentstatus/Makefile new file mode 100644 index 00000000000..ded7a36092d --- /dev/null +++ b/component/componentstatus/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common diff --git a/component/componentstatus/go.mod b/component/componentstatus/go.mod new file mode 100644 index 00000000000..c02c171b802 --- /dev/null +++ b/component/componentstatus/go.mod @@ -0,0 +1,34 @@ +module go.opentelemetry.io/collector/component/componentstatus + +go 1.21.0 + +require ( + github.com/stretchr/testify v1.9.0 + go.opentelemetry.io/collector/component v0.106.1 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.106.1 // indirect + go.opentelemetry.io/collector/pdata v1.12.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/net v0.26.0 // indirect + 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-20240528184218-531527333157 // 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 +) + +replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry + +replace go.opentelemetry.io/collector/component => ../ + +replace go.opentelemetry.io/collector/pdata => ../../pdata diff --git a/component/componentstatus/go.sum b/component/componentstatus/go.sum new file mode 100644 index 00000000000..147b5cbbcda --- /dev/null +++ b/component/componentstatus/go.sum @@ -0,0 +1,78 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/component/componentstatus/instance.go b/component/componentstatus/instance.go new file mode 100644 index 00000000000..22ea4c8003e --- /dev/null +++ b/component/componentstatus/instance.go @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package componentstatus // import "go.opentelemetry.io/collector/component/componentstatus" + +import "go.opentelemetry.io/collector/component" + +// InstanceID uniquely identifies a component instance +// +// TODO: consider moving this struct to a new package/module like `extension/statuswatcher` +// https://github.com/open-telemetry/opentelemetry-collector/issues/10764 +type InstanceID struct { + ID component.ID + Kind component.Kind + PipelineIDs map[component.ID]struct{} +} diff --git a/component/componentstatus/status.go b/component/componentstatus/status.go new file mode 100644 index 00000000000..6f016cf0797 --- /dev/null +++ b/component/componentstatus/status.go @@ -0,0 +1,139 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Package componentstatus is an experimental module that defines how components should +// report health statues, how collector hosts should facilitate component status reporting, +// and how extensions should watch for new component statuses. +// +// This package is currently under development and is exempt from the Collector SIG's +// breaking change policy. +package componentstatus // import "go.opentelemetry.io/collector/component/componentstatus" + +import ( + "time" +) + +// Watcher is an extra interface for Extension hosted by the OpenTelemetry +// Collector that is to be implemented by extensions interested in changes to component +// status. +// +// TODO: consider moving this interface to a new package/module like `extension/statuswatcher` +// https://github.com/open-telemetry/opentelemetry-collector/issues/10764 +type Watcher interface { + // ComponentStatusChanged notifies about a change in the source component status. + // Extensions that implement this interface must be ready that the ComponentStatusChanged + // may be called before, after or concurrently with calls to Component.Start() and Component.Shutdown(). + // The function may be called concurrently with itself. + ComponentStatusChanged(source *InstanceID, event *Event) +} + +type Status int32 + +// Enumeration of possible component statuses +const ( + // StatusNone indicates absence of component status. + StatusNone Status = iota + // StatusStarting indicates the component is starting. + StatusStarting + // StatusOK indicates the component is running without issues. + StatusOK + // StatusRecoverableError indicates that the component has experienced a transient error and may recover. + StatusRecoverableError + // StatusPermanentError indicates that the component has detected a condition at runtime that will need human intervention to fix. The collector will continue to run in a degraded mode. + StatusPermanentError + // StatusFatalError indicates that the collector has experienced a fatal runtime error and will shut down. + StatusFatalError + // StatusStopping indicates that the component is in the process of shutting down. + StatusStopping + // StatusStopped indicates that the component has completed shutdown. + StatusStopped +) + +// String returns a string representation of a Status +func (s Status) String() string { + switch s { + case StatusStarting: + return "StatusStarting" + case StatusOK: + return "StatusOK" + case StatusRecoverableError: + return "StatusRecoverableError" + case StatusPermanentError: + return "StatusPermanentError" + case StatusFatalError: + return "StatusFatalError" + case StatusStopping: + return "StatusStopping" + case StatusStopped: + return "StatusStopped" + } + return "StatusNone" +} + +// Event contains a status and timestamp, and can contain an error +type Event struct { + status Status + err error + // TODO: consider if a timestamp is necessary in the default Event struct or is needed only for the healthcheckv2 extension + // https://github.com/open-telemetry/opentelemetry-collector/issues/10763 + timestamp time.Time +} + +// Status returns the Status (enum) associated with the Event +func (ev *Event) Status() Status { + return ev.status +} + +// Err returns the error associated with the Event. +func (ev *Event) Err() error { + return ev.err +} + +// Timestamp returns the timestamp associated with the Event +func (ev *Event) Timestamp() time.Time { + return ev.timestamp +} + +// NewEvent creates and returns a Event with the specified status and sets the timestamp +// time.Now(). To set an error on the event for an error status use one of the dedicated +// constructors (e.g. NewRecoverableErrorEvent, NewPermanentErrorEvent, NewFatalErrorEvent) +func NewEvent(status Status) *Event { + return &Event{ + status: status, + timestamp: time.Now(), + } +} + +// NewRecoverableErrorEvent wraps a transient error +// passed as argument as a Event with a status StatusRecoverableError +// and a timestamp set to time.Now(). +func NewRecoverableErrorEvent(err error) *Event { + ev := NewEvent(StatusRecoverableError) + ev.err = err + return ev +} + +// NewPermanentErrorEvent wraps an error requiring human intervention to fix +// passed as argument as a Event with a status StatusPermanentError +// and a timestamp set to time.Now(). +func NewPermanentErrorEvent(err error) *Event { + ev := NewEvent(StatusPermanentError) + ev.err = err + return ev +} + +// NewFatalErrorEvent wraps the fatal runtime error passed as argument as a Event +// with a status StatusFatalError and a timestamp set to time.Now(). +func NewFatalErrorEvent(err error) *Event { + ev := NewEvent(StatusFatalError) + ev.err = err + return ev +} + +// StatusIsError returns true for error statuses (e.g. StatusRecoverableError, +// StatusPermanentError, or StatusFatalError) +func StatusIsError(status Status) bool { + return status == StatusRecoverableError || + status == StatusPermanentError || + status == StatusFatalError +} diff --git a/component/componentstatus/status_test.go b/component/componentstatus/status_test.go new file mode 100644 index 00000000000..7d66f2c5c3d --- /dev/null +++ b/component/componentstatus/status_test.go @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +package componentstatus + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewStatusEvent(t *testing.T) { + statuses := []Status{ + StatusStarting, + StatusOK, + StatusRecoverableError, + StatusPermanentError, + StatusFatalError, + StatusStopping, + StatusStopped, + } + + for _, status := range statuses { + t.Run(fmt.Sprintf("%s without error", status), func(t *testing.T) { + ev := NewEvent(status) + require.Equal(t, status, ev.Status()) + require.Nil(t, ev.Err()) + require.False(t, ev.Timestamp().IsZero()) + }) + } +} + +func TestStatusEventsWithError(t *testing.T) { + statusConstructorMap := map[Status]func(error) *Event{ + StatusRecoverableError: NewRecoverableErrorEvent, + StatusPermanentError: NewPermanentErrorEvent, + StatusFatalError: NewFatalErrorEvent, + } + + for status, newEvent := range statusConstructorMap { + t.Run(fmt.Sprintf("error status constructor for: %s", status), func(t *testing.T) { + ev := newEvent(assert.AnError) + require.Equal(t, status, ev.Status()) + require.Equal(t, assert.AnError, ev.Err()) + require.False(t, ev.Timestamp().IsZero()) + }) + } +} + +func TestStatusIsError(t *testing.T) { + for _, tc := range []struct { + status Status + isError bool + }{ + { + status: StatusStarting, + isError: false, + }, + { + status: StatusOK, + isError: false, + }, + { + status: StatusRecoverableError, + isError: true, + }, + { + status: StatusPermanentError, + isError: true, + }, + { + status: StatusFatalError, + isError: true, + }, + { + status: StatusStopping, + isError: false, + }, + { + status: StatusStopped, + isError: false, + }, + } { + name := fmt.Sprintf("StatusIsError(%s) is %t", tc.status, tc.isError) + t.Run(name, func(t *testing.T) { + assert.Equal(t, tc.isError, StatusIsError(tc.status)) + }) + } +} diff --git a/versions.yaml b/versions.yaml index 390e7294c41..28d454d7549 100644 --- a/versions.yaml +++ b/versions.yaml @@ -20,6 +20,7 @@ module-sets: - go.opentelemetry.io/collector/cmd/builder - go.opentelemetry.io/collector/cmd/mdatagen - go.opentelemetry.io/collector/component + - go.opentelemetry.io/collector/component/componentstatus - go.opentelemetry.io/collector/component/componentprofiles - go.opentelemetry.io/collector/confmap - go.opentelemetry.io/collector/confmap/converter/expandconverter