Move error out of `ReportComponentStatus` function signature, use `ReportStatus` instead (#9175)
Fixes #9148
This commit is contained in:
parent
6ed7ad1073
commit
c5a2c78d61
|
|
@ -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: breaking
|
||||
|
||||
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
|
||||
component: status
|
||||
|
||||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
|
||||
note: Deprecate `ReportComponentStatus` in favor of `ReportStatus`. This new function does not return an error.
|
||||
|
||||
# One or more tracking issues or pull requests related to the change
|
||||
issues: [9148]
|
||||
|
||||
# (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: []
|
||||
|
|
@ -21,8 +21,7 @@ func NewNopTelemetrySettings() component.TelemetrySettings {
|
|||
MeterProvider: noopmetric.NewMeterProvider(),
|
||||
MetricsLevel: configtelemetry.LevelNone,
|
||||
Resource: pcommon.NewResource(),
|
||||
ReportComponentStatus: func(*component.StatusEvent) error {
|
||||
return nil
|
||||
ReportStatus: func(*component.StatusEvent) {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@ type TelemetrySettings struct {
|
|||
|
||||
// ReportComponentStatus allows a component to report runtime changes in status. The service
|
||||
// will automatically report status for a component during startup and shutdown. Components can
|
||||
// use this method to report status after start and before shutdown. ReportComponentStatus
|
||||
// will only return errors if the API used incorrectly. The two scenarios where an error will
|
||||
// be returned are:
|
||||
//
|
||||
// - An illegal state transition
|
||||
// - Calling this method before component startup
|
||||
//
|
||||
// If the API is being used properly, these errors are safe to ignore.
|
||||
// use this method to report status after start and before shutdown.
|
||||
// Deprecated: [v0.92.0] This function will be removed in a future release.
|
||||
// Use ReportStatus instead.
|
||||
ReportComponentStatus func(*StatusEvent) error
|
||||
|
||||
// ReportStatus allows a component to report runtime changes in status. The service
|
||||
// will automatically report status for a component during startup and shutdown. Components can
|
||||
// use this method to report status after start and before shutdown.
|
||||
ReportStatus func(*StatusEvent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,17 +29,14 @@ type Map[K comparable, V component.Component] struct {
|
|||
func (m *Map[K, V]) LoadOrStore(key K, create func() (V, error), telemetrySettings *component.TelemetrySettings) (*Component[V], error) {
|
||||
if c, ok := m.components[key]; ok {
|
||||
// If we haven't already seen this telemetry settings, this shared component represents
|
||||
// another instance. Wrap ReportComponentStatus to report for all instances this shared
|
||||
// another instance. Wrap ReportStatus to report for all instances this shared
|
||||
// component represents.
|
||||
if _, ok := c.seenSettings[telemetrySettings]; !ok {
|
||||
c.seenSettings[telemetrySettings] = struct{}{}
|
||||
prev := c.telemetry.ReportComponentStatus
|
||||
c.telemetry.ReportComponentStatus = func(ev *component.StatusEvent) error {
|
||||
err := telemetrySettings.ReportComponentStatus(ev)
|
||||
if prevErr := prev(ev); prevErr != nil {
|
||||
err = prevErr
|
||||
}
|
||||
return err
|
||||
prev := c.telemetry.ReportStatus
|
||||
c.telemetry.ReportStatus = func(ev *component.StatusEvent) {
|
||||
telemetrySettings.ReportStatus(ev)
|
||||
prev(ev)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
|
|
@ -89,9 +86,9 @@ func (c *Component[V]) Start(ctx context.Context, host component.Host) error {
|
|||
// telemetry settings to keep status in sync and avoid race conditions. This logic duplicates
|
||||
// and takes priority over the automated status reporting that happens in graph, making the
|
||||
// status reporting in graph a no-op.
|
||||
_ = c.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusStarting))
|
||||
c.telemetry.ReportStatus(component.NewStatusEvent(component.StatusStarting))
|
||||
if err = c.component.Start(ctx, host); err != nil {
|
||||
_ = c.telemetry.ReportComponentStatus(component.NewPermanentErrorEvent(err))
|
||||
c.telemetry.ReportStatus(component.NewPermanentErrorEvent(err))
|
||||
}
|
||||
})
|
||||
return err
|
||||
|
|
@ -105,12 +102,12 @@ func (c *Component[V]) Shutdown(ctx context.Context) error {
|
|||
// telemetry settings to keep status in sync and avoid race conditions. This logic duplicates
|
||||
// and takes priority over the automated status reporting that happens in graph, making the
|
||||
// status reporting in graph a no-op.
|
||||
_ = c.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusStopping))
|
||||
c.telemetry.ReportStatus(component.NewStatusEvent(component.StatusStopping))
|
||||
err = c.component.Shutdown(ctx)
|
||||
if err != nil {
|
||||
_ = c.telemetry.ReportComponentStatus(component.NewPermanentErrorEvent(err))
|
||||
c.telemetry.ReportStatus(component.NewPermanentErrorEvent(err))
|
||||
} else {
|
||||
_ = c.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusStopped))
|
||||
c.telemetry.ReportStatus(component.NewStatusEvent(component.StatusStopped))
|
||||
}
|
||||
c.removeFunc()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -109,15 +109,13 @@ func TestSharedComponent(t *testing.T) {
|
|||
}
|
||||
func TestSharedComponentsReportStatus(t *testing.T) {
|
||||
reportedStatuses := make(map[*component.InstanceID][]component.Status)
|
||||
newStatusFunc := func() func(*component.StatusEvent) error {
|
||||
newStatusFunc := func() func(*component.StatusEvent) {
|
||||
instanceID := &component.InstanceID{}
|
||||
return func(ev *component.StatusEvent) error {
|
||||
// Use an event with component.StatusNone to simulate an error.
|
||||
return func(ev *component.StatusEvent) {
|
||||
if ev.Status() == component.StatusNone {
|
||||
return assert.AnError
|
||||
return
|
||||
}
|
||||
reportedStatuses[instanceID] = append(reportedStatuses[instanceID], ev.Status())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,10 +126,10 @@ func TestSharedComponentsReportStatus(t *testing.T) {
|
|||
// make a shared component that represents three instances
|
||||
for i := 0; i < 3; i++ {
|
||||
telemetrySettings = newNopTelemetrySettings()
|
||||
telemetrySettings.ReportComponentStatus = newStatusFunc()
|
||||
telemetrySettings.ReportStatus = newStatusFunc()
|
||||
// The initial settings for the shared component need to match the ones passed to the first
|
||||
// invocation of LoadOrStore so that underlying telemetry settings reference can be used to
|
||||
// wrap ReportComponentStatus for subsequently added "instances".
|
||||
// wrap ReportStatus for subsequently added "instances".
|
||||
if i == 0 {
|
||||
comp.telemetry = telemetrySettings
|
||||
}
|
||||
|
|
@ -152,24 +150,18 @@ func TestSharedComponentsReportStatus(t *testing.T) {
|
|||
telemetrySettings,
|
||||
)
|
||||
|
||||
err := comp.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusStarting))
|
||||
require.NoError(t, err)
|
||||
comp.telemetry.ReportStatus(component.NewStatusEvent(component.StatusStarting))
|
||||
|
||||
// ok
|
||||
err = comp.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusOK))
|
||||
require.NoError(t, err)
|
||||
comp.telemetry.ReportStatus(component.NewStatusEvent(component.StatusOK))
|
||||
|
||||
// simulate an error
|
||||
err = comp.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusNone))
|
||||
require.ErrorIs(t, err, assert.AnError)
|
||||
comp.telemetry.ReportStatus(component.NewStatusEvent(component.StatusNone))
|
||||
|
||||
// stopping
|
||||
err = comp.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusStopping))
|
||||
require.NoError(t, err)
|
||||
comp.telemetry.ReportStatus(component.NewStatusEvent(component.StatusStopping))
|
||||
|
||||
// stopped
|
||||
err = comp.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusStopped))
|
||||
require.NoError(t, err)
|
||||
comp.telemetry.ReportStatus(component.NewStatusEvent(component.StatusStopped))
|
||||
|
||||
// The shared component represents 3 component instances. Reporting status for the shared
|
||||
// component should report status for each of the instances it represents.
|
||||
|
|
@ -227,11 +219,10 @@ func TestReportStatusOnStartShutdown(t *testing.T) {
|
|||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
reportedStatuses := make(map[*component.InstanceID][]component.Status)
|
||||
newStatusFunc := func() func(*component.StatusEvent) error {
|
||||
newStatusFunc := func() func(*component.StatusEvent) {
|
||||
instanceID := &component.InstanceID{}
|
||||
return func(ev *component.StatusEvent) error {
|
||||
return func(ev *component.StatusEvent) {
|
||||
reportedStatuses[instanceID] = append(reportedStatuses[instanceID], ev.Status())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
base := &baseComponent{}
|
||||
|
|
@ -250,7 +241,7 @@ func TestReportStatusOnStartShutdown(t *testing.T) {
|
|||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
telemetrySettings := newNopTelemetrySettings()
|
||||
telemetrySettings.ReportComponentStatus = newStatusFunc()
|
||||
telemetrySettings.ReportStatus = newStatusFunc()
|
||||
if i == 0 {
|
||||
base.telemetry = telemetrySettings
|
||||
}
|
||||
|
|
@ -266,8 +257,7 @@ func TestReportStatusOnStartShutdown(t *testing.T) {
|
|||
require.Equal(t, tc.startErr, err)
|
||||
|
||||
if tc.startErr == nil {
|
||||
err = comp.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusOK))
|
||||
require.NoError(t, err)
|
||||
comp.telemetry.ReportStatus(component.NewStatusEvent(component.StatusOK))
|
||||
|
||||
err = comp.Shutdown(context.Background())
|
||||
require.Equal(t, tc.shutdownErr, err)
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ type unhealthyProcessor struct {
|
|||
|
||||
func (p unhealthyProcessor) Start(_ context.Context, _ component.Host) error {
|
||||
go func() {
|
||||
_ = p.telemetry.ReportComponentStatus(component.NewStatusEvent(component.StatusRecoverableError))
|
||||
p.telemetry.ReportStatus(component.NewStatusEvent(component.StatusRecoverableError))
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,18 +37,18 @@ func (bes *Extensions) Start(ctx context.Context, host component.Host) error {
|
|||
extLogger.Info("Extension is starting...")
|
||||
instanceID := bes.instanceIDs[extID]
|
||||
ext := bes.extMap[extID]
|
||||
_ = bes.telemetry.Status.ReportComponentStatus(
|
||||
bes.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewStatusEvent(component.StatusStarting),
|
||||
)
|
||||
if err := ext.Start(ctx, components.NewHostWrapper(host, extLogger)); err != nil {
|
||||
_ = bes.telemetry.Status.ReportComponentStatus(
|
||||
bes.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewPermanentErrorEvent(err),
|
||||
)
|
||||
return err
|
||||
}
|
||||
_ = bes.telemetry.Status.ReportComponentOKIfStarting(instanceID)
|
||||
bes.telemetry.Status.ReportOKIfStarting(instanceID)
|
||||
extLogger.Info("Extension started.")
|
||||
}
|
||||
return nil
|
||||
|
|
@ -62,19 +62,19 @@ func (bes *Extensions) Shutdown(ctx context.Context) error {
|
|||
extID := bes.extensionIDs[i]
|
||||
instanceID := bes.instanceIDs[extID]
|
||||
ext := bes.extMap[extID]
|
||||
_ = bes.telemetry.Status.ReportComponentStatus(
|
||||
bes.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewStatusEvent(component.StatusStopping),
|
||||
)
|
||||
if err := ext.Shutdown(ctx); err != nil {
|
||||
_ = bes.telemetry.Status.ReportComponentStatus(
|
||||
bes.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewPermanentErrorEvent(err),
|
||||
)
|
||||
errs = multierr.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
_ = bes.telemetry.Status.ReportComponentStatus(
|
||||
bes.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewStatusEvent(component.StatusStopped),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -434,6 +434,8 @@ func TestStatusReportedOnStartupShutdown(t *testing.T) {
|
|||
var actualStatuses []*component.StatusEvent
|
||||
rep := status.NewReporter(func(id *component.InstanceID, ev *component.StatusEvent) {
|
||||
actualStatuses = append(actualStatuses, ev)
|
||||
}, func(err error) {
|
||||
require.NoError(t, err)
|
||||
})
|
||||
extensions.telemetry.Status = rep
|
||||
rep.Ready()
|
||||
|
|
|
|||
|
|
@ -388,20 +388,20 @@ func (g *Graph) StartAll(ctx context.Context, host component.Host) error {
|
|||
}
|
||||
|
||||
instanceID := g.instanceIDs[node.ID()]
|
||||
_ = g.telemetry.Status.ReportComponentStatus(
|
||||
g.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewStatusEvent(component.StatusStarting),
|
||||
)
|
||||
|
||||
if compErr := comp.Start(ctx, host); compErr != nil {
|
||||
_ = g.telemetry.Status.ReportComponentStatus(
|
||||
g.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewPermanentErrorEvent(compErr),
|
||||
)
|
||||
return compErr
|
||||
}
|
||||
|
||||
_ = g.telemetry.Status.ReportComponentOKIfStarting(instanceID)
|
||||
g.telemetry.Status.ReportOKIfStarting(instanceID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -427,21 +427,21 @@ func (g *Graph) ShutdownAll(ctx context.Context) error {
|
|||
}
|
||||
|
||||
instanceID := g.instanceIDs[node.ID()]
|
||||
_ = g.telemetry.Status.ReportComponentStatus(
|
||||
g.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewStatusEvent(component.StatusStopping),
|
||||
)
|
||||
|
||||
if compErr := comp.Shutdown(ctx); compErr != nil {
|
||||
errs = multierr.Append(errs, compErr)
|
||||
_ = g.telemetry.Status.ReportComponentStatus(
|
||||
g.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewPermanentErrorEvent(compErr),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
_ = g.telemetry.Status.ReportComponentStatus(
|
||||
g.telemetry.Status.ReportStatus(
|
||||
instanceID,
|
||||
component.NewStatusEvent(component.StatusStopped),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2337,6 +2337,7 @@ func TestStatusReportedOnStartupShutdown(t *testing.T) {
|
|||
actualStatuses := make(map[*component.InstanceID][]*component.StatusEvent)
|
||||
rep := status.NewReporter(func(id *component.InstanceID, ev *component.StatusEvent) {
|
||||
actualStatuses[id] = append(actualStatuses[id], ev)
|
||||
}, func(err error) {
|
||||
})
|
||||
|
||||
pg.telemetry.Status = rep
|
||||
|
|
|
|||
|
|
@ -22,6 +22,6 @@ func NewNopTelemetrySettings() TelemetrySettings {
|
|||
MeterProvider: noopmetric.NewMeterProvider(),
|
||||
MetricsLevel: configtelemetry.LevelNone,
|
||||
Resource: pcommon.NewResource(),
|
||||
Status: status.NewReporter(func(*component.InstanceID, *component.StatusEvent) {}),
|
||||
Status: status.NewReporter(func(*component.InstanceID, *component.StatusEvent) {}, func(err error) {}),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,11 +26,10 @@ func TestNewNopSettings(t *testing.T) {
|
|||
require.Equal(t, noopmetric.NewMeterProvider(), set.MeterProvider)
|
||||
require.Equal(t, configtelemetry.LevelNone, set.MetricsLevel)
|
||||
require.Equal(t, pcommon.NewResource(), set.Resource)
|
||||
require.NoError(t,
|
||||
set.Status.ReportComponentStatus(
|
||||
&component.InstanceID{},
|
||||
component.NewStatusEvent(component.StatusStarting),
|
||||
),
|
||||
set.Status.ReportStatus(
|
||||
&component.InstanceID{},
|
||||
component.NewStatusEvent(component.StatusStarting),
|
||||
)
|
||||
require.NoError(t, set.Status.ReportComponentOKIfStarting(&component.InstanceID{}))
|
||||
set.Status.ReportOKIfStarting(&component.InstanceID{})
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,12 +43,17 @@ type TelemetrySettings struct {
|
|||
// ToComponentTelemetrySettings returns a TelemetrySettings for a specific component derived from
|
||||
// this service level Settings object.
|
||||
func (s TelemetrySettings) ToComponentTelemetrySettings(id *component.InstanceID) component.TelemetrySettings {
|
||||
statusFunc := status.NewReportStatusFunc(id, s.Status.ReportStatus)
|
||||
return component.TelemetrySettings{
|
||||
Logger: s.Logger,
|
||||
TracerProvider: s.TracerProvider,
|
||||
MeterProvider: s.MeterProvider,
|
||||
MetricsLevel: s.MetricsLevel,
|
||||
Resource: s.Resource,
|
||||
ReportComponentStatus: status.NewComponentStatusFunc(id, s.Status.ReportComponentStatus),
|
||||
Logger: s.Logger,
|
||||
TracerProvider: s.TracerProvider,
|
||||
MeterProvider: s.MeterProvider,
|
||||
MetricsLevel: s.MetricsLevel,
|
||||
Resource: s.Resource,
|
||||
ReportComponentStatus: func(event *component.StatusEvent) error {
|
||||
statusFunc(event)
|
||||
return nil
|
||||
},
|
||||
ReportStatus: statusFunc,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,17 +24,17 @@ func TestSettings(t *testing.T) {
|
|||
MeterProvider: noopmetric.NewMeterProvider(),
|
||||
MetricsLevel: configtelemetry.LevelNone,
|
||||
Resource: pcommon.NewResource(),
|
||||
Status: status.NewReporter(func(*component.InstanceID, *component.StatusEvent) {}),
|
||||
Status: status.NewReporter(
|
||||
func(*component.InstanceID, *component.StatusEvent) {},
|
||||
func(err error) { require.NoError(t, err) }),
|
||||
}
|
||||
set.Status.Ready()
|
||||
require.NoError(t,
|
||||
set.Status.ReportComponentStatus(
|
||||
&component.InstanceID{},
|
||||
component.NewStatusEvent(component.StatusStarting),
|
||||
),
|
||||
set.Status.ReportStatus(
|
||||
&component.InstanceID{},
|
||||
component.NewStatusEvent(component.StatusStarting),
|
||||
)
|
||||
require.NoError(t, set.Status.ReportComponentOKIfStarting(&component.InstanceID{}))
|
||||
set.Status.ReportOKIfStarting(&component.InstanceID{})
|
||||
|
||||
compSet := set.ToComponentTelemetrySettings(&component.InstanceID{})
|
||||
require.NoError(t, compSet.ReportComponentStatus(component.NewStatusEvent(component.StatusStarting)))
|
||||
compSet.ReportStatus(component.NewStatusEvent(component.StatusStarting))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,26 +86,31 @@ func newFSM(onTransition onTransitionFunc) *fsm {
|
|||
// NotifyStatusFunc is the receiver of status events after successful state transitions
|
||||
type NotifyStatusFunc func(*component.InstanceID, *component.StatusEvent)
|
||||
|
||||
// ServiceStatusFunc is the expected type of ReportComponentStatus for servicetelemetry.Settings
|
||||
type ServiceStatusFunc func(*component.InstanceID, *component.StatusEvent) error
|
||||
// InvalidTransitionFunc is the receiver of invalid transition errors
|
||||
type InvalidTransitionFunc func(error)
|
||||
|
||||
// errStatusNotReady is returned when trying to report status before service start
|
||||
var errStatusNotReady = errors.New("report component status is not ready until service start")
|
||||
// ServiceStatusFunc is the expected type of ReportStatus for servicetelemetry.Settings
|
||||
type ServiceStatusFunc func(*component.InstanceID, *component.StatusEvent)
|
||||
|
||||
// ErrStatusNotReady is returned when trying to report status before service start
|
||||
var ErrStatusNotReady = errors.New("report component status is not ready until service start")
|
||||
|
||||
// Reporter handles component status reporting
|
||||
type Reporter struct {
|
||||
mu sync.Mutex
|
||||
ready bool
|
||||
fsmMap map[*component.InstanceID]*fsm
|
||||
onStatusChange NotifyStatusFunc
|
||||
mu sync.Mutex
|
||||
ready bool
|
||||
fsmMap map[*component.InstanceID]*fsm
|
||||
onStatusChange NotifyStatusFunc
|
||||
onInvalidTransition InvalidTransitionFunc
|
||||
}
|
||||
|
||||
// NewReporter returns a reporter that will invoke the NotifyStatusFunc when a component's status
|
||||
// has changed.
|
||||
func NewReporter(onStatusChange NotifyStatusFunc) *Reporter {
|
||||
func NewReporter(onStatusChange NotifyStatusFunc, onInvalidTransition InvalidTransitionFunc) *Reporter {
|
||||
return &Reporter{
|
||||
fsmMap: make(map[*component.InstanceID]*fsm),
|
||||
onStatusChange: onStatusChange,
|
||||
fsmMap: make(map[*component.InstanceID]*fsm),
|
||||
onStatusChange: onStatusChange,
|
||||
onInvalidTransition: onInvalidTransition,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,30 +122,52 @@ func (r *Reporter) Ready() {
|
|||
}
|
||||
|
||||
// ReportComponentStatus reports status for the given InstanceID
|
||||
// Deprecated: [v0.92.0] This function will be removed in a future release.
|
||||
// Use ReportStatus instead.
|
||||
func (r *Reporter) ReportComponentStatus(
|
||||
id *component.InstanceID,
|
||||
ev *component.StatusEvent,
|
||||
) error {
|
||||
r.ReportStatus(id, ev)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReportStatus reports status for the given InstanceID
|
||||
func (r *Reporter) ReportStatus(
|
||||
id *component.InstanceID,
|
||||
ev *component.StatusEvent,
|
||||
) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if !r.ready {
|
||||
return errStatusNotReady
|
||||
r.onInvalidTransition(ErrStatusNotReady)
|
||||
} else {
|
||||
if err := r.componentFSM(id).transition(ev); err != nil {
|
||||
r.onInvalidTransition(err)
|
||||
}
|
||||
}
|
||||
return r.componentFSM(id).transition(ev)
|
||||
}
|
||||
|
||||
// ReportComponentOkIfStarting reports StatusOK if the component's current status is Starting
|
||||
// Deprecated: [v0.92.0] This function will be removed in a future release.
|
||||
// Use ReportOKIfStarting instead.
|
||||
func (r *Reporter) ReportComponentOKIfStarting(id *component.InstanceID) error {
|
||||
r.ReportOKIfStarting(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reporter) ReportOKIfStarting(id *component.InstanceID) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if !r.ready {
|
||||
return errStatusNotReady
|
||||
r.onInvalidTransition(ErrStatusNotReady)
|
||||
}
|
||||
fsm := r.componentFSM(id)
|
||||
if fsm.current.Status() == component.StatusStarting {
|
||||
return fsm.transition(component.NewStatusEvent(component.StatusOK))
|
||||
if err := fsm.transition(component.NewStatusEvent(component.StatusOK)); err != nil {
|
||||
r.onInvalidTransition(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note: a lock must be acquired before calling this method.
|
||||
|
|
@ -153,14 +180,14 @@ func (r *Reporter) componentFSM(id *component.InstanceID) *fsm {
|
|||
return fsm
|
||||
}
|
||||
|
||||
// NewComponentStatusFunc returns a function to be used as ReportComponentStatus for
|
||||
// NewReportStatusFunc returns a function to be used as ReportStatus for
|
||||
// component.TelemetrySettings, which differs from servicetelemetry.Settings in that
|
||||
// the component version is tied to specific component instance.
|
||||
func NewComponentStatusFunc(
|
||||
func NewReportStatusFunc(
|
||||
id *component.InstanceID,
|
||||
srvStatus ServiceStatusFunc,
|
||||
) func(*component.StatusEvent) error {
|
||||
return func(ev *component.StatusEvent) error {
|
||||
return srvStatus(id, ev)
|
||||
) func(*component.StatusEvent) {
|
||||
return func(ev *component.StatusEvent) {
|
||||
srvStatus(id, ev)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,17 +208,20 @@ func TestStatusFuncs(t *testing.T) {
|
|||
id2: statuses2,
|
||||
}
|
||||
|
||||
rep := NewReporter(statusFunc)
|
||||
comp1Func := NewComponentStatusFunc(id1, rep.ReportComponentStatus)
|
||||
comp2Func := NewComponentStatusFunc(id2, rep.ReportComponentStatus)
|
||||
rep := NewReporter(statusFunc,
|
||||
func(err error) {
|
||||
require.NoError(t, err)
|
||||
})
|
||||
comp1Func := NewReportStatusFunc(id1, rep.ReportStatus)
|
||||
comp2Func := NewReportStatusFunc(id2, rep.ReportStatus)
|
||||
rep.Ready()
|
||||
|
||||
for _, st := range statuses1 {
|
||||
require.NoError(t, comp1Func(component.NewStatusEvent(st)))
|
||||
comp1Func(component.NewStatusEvent(st))
|
||||
}
|
||||
|
||||
for _, st := range statuses2 {
|
||||
require.NoError(t, comp2Func(component.NewStatusEvent(st)))
|
||||
comp2Func(component.NewStatusEvent(st))
|
||||
}
|
||||
|
||||
require.Equal(t, expectedStatuses, actualStatuses)
|
||||
|
|
@ -230,7 +233,10 @@ func TestStatusFuncsConcurrent(t *testing.T) {
|
|||
statusFunc := func(id *component.InstanceID, ev *component.StatusEvent) {
|
||||
count++
|
||||
}
|
||||
rep := NewReporter(statusFunc)
|
||||
rep := NewReporter(statusFunc,
|
||||
func(err error) {
|
||||
require.NoError(t, err)
|
||||
})
|
||||
rep.Ready()
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
|
@ -239,11 +245,11 @@ func TestStatusFuncsConcurrent(t *testing.T) {
|
|||
for _, id := range ids {
|
||||
id := id
|
||||
go func() {
|
||||
compFn := NewComponentStatusFunc(id, rep.ReportComponentStatus)
|
||||
_ = compFn(component.NewStatusEvent(component.StatusStarting))
|
||||
compFn := NewReportStatusFunc(id, rep.ReportStatus)
|
||||
compFn(component.NewStatusEvent(component.StatusStarting))
|
||||
for i := 0; i < 1000; i++ {
|
||||
_ = compFn(component.NewStatusEvent(component.StatusRecoverableError))
|
||||
_ = compFn(component.NewStatusEvent(component.StatusOK))
|
||||
compFn(component.NewStatusEvent(component.StatusRecoverableError))
|
||||
compFn(component.NewStatusEvent(component.StatusOK))
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
|
@ -255,15 +261,19 @@ func TestStatusFuncsConcurrent(t *testing.T) {
|
|||
|
||||
func TestReporterReady(t *testing.T) {
|
||||
statusFunc := func(*component.InstanceID, *component.StatusEvent) {}
|
||||
rep := NewReporter(statusFunc)
|
||||
var err error
|
||||
rep := NewReporter(statusFunc,
|
||||
func(e error) {
|
||||
err = e
|
||||
})
|
||||
id := &component.InstanceID{}
|
||||
|
||||
err := rep.ReportComponentStatus(id, component.NewStatusEvent(component.StatusStarting))
|
||||
require.ErrorIs(t, err, errStatusNotReady)
|
||||
|
||||
rep.ReportStatus(id, component.NewStatusEvent(component.StatusStarting))
|
||||
require.ErrorIs(t, err, ErrStatusNotReady)
|
||||
rep.Ready()
|
||||
|
||||
err = rep.ReportComponentStatus(id, component.NewStatusEvent(component.StatusStarting))
|
||||
err = nil
|
||||
rep.ReportStatus(id, component.NewStatusEvent(component.StatusStarting))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
@ -324,18 +334,19 @@ func TestReportComponentOKIfStarting(t *testing.T) {
|
|||
func(_ *component.InstanceID, ev *component.StatusEvent) {
|
||||
receivedStatuses = append(receivedStatuses, ev.Status())
|
||||
},
|
||||
func(err error) {
|
||||
require.NoError(t, err)
|
||||
},
|
||||
)
|
||||
rep.Ready()
|
||||
|
||||
id := &component.InstanceID{}
|
||||
for _, status := range tc.initialStatuses {
|
||||
err := rep.ReportComponentStatus(id, component.NewStatusEvent(status))
|
||||
require.NoError(t, err)
|
||||
rep.ReportStatus(id, component.NewStatusEvent(status))
|
||||
}
|
||||
|
||||
err := rep.ReportComponentOKIfStarting(id)
|
||||
rep.ReportOKIfStarting(id)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedStatuses, receivedStatuses)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ package service // import "go.opentelemetry.io/collector/service"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
|
|
@ -113,7 +114,12 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) {
|
|||
MetricsLevel: cfg.Telemetry.Metrics.Level,
|
||||
// Construct telemetry attributes from build info and config's resource attributes.
|
||||
Resource: pcommonRes,
|
||||
Status: status.NewReporter(srv.host.notifyComponentStatusChange),
|
||||
Status: status.NewReporter(srv.host.notifyComponentStatusChange, func(err error) {
|
||||
if errors.Is(err, status.ErrStatusNotReady) {
|
||||
srv.telemetry.Logger().Warn("Invalid transition", zap.Error(err))
|
||||
}
|
||||
// ignore other errors as they represent invalid state transitions and are considered benign.
|
||||
}),
|
||||
}
|
||||
|
||||
if err = srv.telemetryInitializer.init(res, srv.telemetrySettings, cfg.Telemetry, set.AsyncErrorChannel); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue