Skip to content

Commit d9101ba

Browse files
authored
fix: unit test failures while using instana.InitCollector() API (#1012)
* fix: unit test failures while using instana.InitCollector() API Co-authored-by: Nithin Puthenveettil <[email protected]> Co-authored-by: Sanoj Subran <[email protected]>
1 parent 1a76bdd commit d9101ba

File tree

4 files changed

+110
-50
lines changed

4 files changed

+110
-50
lines changed

collector.go

+37-21
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package instana
44

55
import (
66
"context"
7+
"fmt"
8+
"sync"
79

810
ot "github.com/opentracing/opentracing-go"
911
)
@@ -25,38 +27,52 @@ type Collector struct {
2527

2628
var _ TracerLogger = (*Collector)(nil)
2729

30+
var (
31+
once sync.Once
32+
muc sync.Mutex
33+
)
34+
2835
// InitCollector creates a new [Collector]
2936
func InitCollector(opts *Options) TracerLogger {
3037

31-
// if instana.C is already an instance of Collector, we just return
32-
if _, ok := C.(*Collector); ok {
33-
C.Warn("InitCollector was previously called. instana.C is reused")
34-
return C
35-
}
38+
once.Do(func() {
39+
if opts == nil {
40+
opts = &Options{
41+
Recorder: NewRecorder(),
42+
}
43+
}
3644

37-
if opts == nil {
38-
opts = &Options{
39-
Recorder: NewRecorder(),
45+
if opts.Recorder == nil {
46+
opts.Recorder = NewRecorder()
4047
}
41-
}
4248

43-
if opts.Recorder == nil {
44-
opts.Recorder = NewRecorder()
45-
}
49+
StartMetrics(opts)
4650

47-
StartMetrics(opts)
51+
tracer := &tracerS{
52+
recorder: opts.Recorder,
53+
}
4854

49-
tracer := &tracerS{
50-
recorder: opts.Recorder,
51-
}
55+
c = &Collector{
56+
t: tracer,
57+
LeveledLogger: defaultLogger,
58+
Sensor: NewSensorWithTracer(tracer),
59+
}
60+
61+
})
62+
63+
return c
64+
}
65+
66+
// GetCollector return the instance of instana Collector
67+
func GetCollector() (TracerLogger, error) {
68+
muc.Lock()
69+
defer muc.Unlock()
5270

53-
C = &Collector{
54-
t: tracer,
55-
LeveledLogger: defaultLogger,
56-
Sensor: NewSensorWithTracer(tracer),
71+
if _, ok := c.(*Collector); !ok {
72+
return c, fmt.Errorf("collector has not been initialised yet. Please use InitCollector first")
5773
}
5874

59-
return C
75+
return c, nil
6076
}
6177

6278
// Extract() returns a SpanContext instance given `format` and `carrier`. It matches [opentracing.Tracer.Extract].

collector_test.go

+53-24
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"net/http"
88
"net/http/httptest"
9+
"sync"
910
"testing"
1011

1112
instana "github.com/instana/go-sensor"
@@ -16,22 +17,25 @@ import (
1617
)
1718

1819
func Test_Collector_Noop(t *testing.T) {
19-
assert.NotNil(t, instana.C, "instana.C should never be nil and be initialized as noop")
20+
c, err := instana.GetCollector()
21+
assert.Error(t, err, "should return error as collector has not been initialized yet.")
2022

21-
sc, err := instana.C.Extract(nil, nil)
23+
assert.NotNil(t, c, "instana collector should never be nil and be initialized as noop")
24+
25+
sc, err := c.Extract(nil, nil)
2226
assert.Nil(t, sc)
2327
assert.Error(t, err)
24-
assert.Nil(t, instana.C.StartSpan(""))
25-
assert.Nil(t, instana.C.LegacySensor())
28+
assert.Nil(t, c.StartSpan(""))
29+
assert.Nil(t, c.LegacySensor())
2630
}
2731

2832
func Test_Collector_LegacySensor(t *testing.T) {
2933
recorder := instana.NewTestRecorder()
3034
c := instana.InitCollector(&instana.Options{AgentClient: alwaysReadyClient{}, Recorder: recorder})
3135
s := c.LegacySensor()
32-
defer instana.ShutdownSensor()
36+
defer instana.ShutdownCollector()
3337

34-
assert.NotNil(t, instana.C.LegacySensor())
38+
assert.NotNil(t, c.LegacySensor())
3539

3640
h := instana.TracingHandlerFunc(s, "/{action}", func(w http.ResponseWriter, req *http.Request) {
3741
fmt.Fprintln(w, "Ok")
@@ -41,30 +45,55 @@ func Test_Collector_LegacySensor(t *testing.T) {
4145

4246
h.ServeHTTP(httptest.NewRecorder(), req)
4347

44-
assert.Len(t, recorder.GetQueuedSpans(), 1, "Instrumentations should still work fine with instana.C.LegacySensor()")
48+
assert.Len(t, recorder.GetQueuedSpans(), 1, "Instrumentations should still work fine with LegacySensor() method")
4549
}
4650

4751
func Test_Collector_Singleton(t *testing.T) {
48-
instana.C = nil
4952
var ok bool
5053
var instance instana.TracerLogger
5154

52-
_, ok = instana.C.(*instana.Collector)
53-
assert.False(t, ok, "instana.C is noop before InitCollector is called")
55+
c, err := instana.GetCollector()
56+
assert.Error(t, err, "should return error as collector has not been initialized yet.")
57+
58+
defer instana.ShutdownCollector()
59+
60+
_, ok = c.(*instana.Collector)
61+
assert.False(t, ok, "instana collector is noop before InitCollector is called")
62+
63+
c = instana.InitCollector(instana.DefaultOptions())
64+
65+
instance, ok = c.(*instana.Collector)
66+
assert.True(t, ok, "instana collector is of type instana.Collector after InitCollector is called")
67+
68+
c = instana.InitCollector(instana.DefaultOptions())
5469

55-
instana.InitCollector(instana.DefaultOptions())
70+
assert.Equal(t, c, instance, "instana collector is singleton and should not be reassigned if InitCollector is called again")
71+
}
72+
73+
func Test_InitCollector_With_Goroutines(t *testing.T) {
74+
75+
defer instana.ShutdownCollector()
5676

57-
instance, ok = instana.C.(*instana.Collector)
58-
assert.True(t, ok, "instana.C is of type instana.Collector after InitCollector is called")
77+
var wg sync.WaitGroup
78+
wg.Add(3)
5979

60-
instana.InitCollector(instana.DefaultOptions())
80+
for i := 0; i < 3; i++ {
81+
go func(id int) {
82+
defer wg.Done()
83+
c := instana.InitCollector(instana.DefaultOptions())
6184

62-
assert.Equal(t, instana.C, instance, "instana.C is singleton and should not be reassigned if InitCollector is called again")
85+
_, ok := c.(*instana.Collector)
86+
assert.True(t, ok, "instana collector is of type instana.Collector after InitCollector is called")
87+
88+
assert.NotNil(t, c)
89+
}(i)
90+
}
91+
wg.Wait()
6392
}
6493

6594
func Test_Collector_EmbeddedTracer(t *testing.T) {
66-
instana.C = nil
6795
c := instana.InitCollector(nil)
96+
defer instana.ShutdownCollector()
6897

6998
sp := c.StartSpan("my-span")
7099

@@ -92,18 +121,18 @@ func Test_Collector_EmbeddedTracer(t *testing.T) {
92121
}
93122

94123
func Test_Collector_Logger(t *testing.T) {
95-
instana.C = nil
96-
instana.InitCollector(nil)
124+
c := instana.InitCollector(nil)
125+
defer instana.ShutdownCollector()
97126

98127
l := &mylogger{}
99128

100-
instana.C.SetLogger(l)
129+
c.SetLogger(l)
101130

102-
instana.C.Debug()
103-
instana.C.Info()
104-
instana.C.Warn()
105-
instana.C.Error()
106-
instana.C.Error()
131+
c.Debug()
132+
c.Info()
133+
c.Warn()
134+
c.Error()
135+
c.Error()
107136

108137
assert.Equal(t, 1, l.counter["debug"])
109138
assert.Equal(t, 1, l.counter["info"])

instrumentation_http_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,17 @@ func BenchmarkTracingNamedHandlerFunc(b *testing.B) {
4646
}
4747

4848
func TestTracingNamedHandlerFunc_Write(t *testing.T) {
49+
recorder := instana.NewTestRecorder()
4950
opts := &instana.Options{
5051
Service: "go-sensor-test",
5152
Tracer: instana.TracerOptions{
5253
CollectableHTTPHeaders: []string{"x-custom-header-1", "x-custom-header-2"},
5354
},
5455
AgentClient: alwaysReadyClient{},
56+
Recorder: recorder,
5557
}
5658

57-
recorder := instana.NewTestRecorder()
58-
s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(opts, recorder))
59+
s := instana.InitCollector(opts)
5960
defer instana.ShutdownSensor()
6061

6162
h := instana.TracingNamedHandlerFunc(s, "action", "/{action}", func(w http.ResponseWriter, req *http.Request) {

sensor.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ var (
8686
muSensor sync.Mutex
8787
binaryName = filepath.Base(os.Args[0])
8888
processStartedAt = time.Now()
89-
C TracerLogger
89+
c TracerLogger
9090
)
9191

9292
func init() {
93-
C = newNoopCollector()
93+
c = newNoopCollector()
9494
}
9595

9696
func newSensor(options *Options) *sensorS {
@@ -276,12 +276,26 @@ func Flush(ctx context.Context) error {
276276

277277
// ShutdownSensor cleans up the internal global sensor reference. The next time that instana.InitSensor is called,
278278
// directly or indirectly, the internal sensor will be reinitialized.
279+
//
280+
// Deprecated: Use [ShutdownCollector] instead.
279281
func ShutdownSensor() {
280282
muSensor.Lock()
283+
defer muSensor.Unlock()
281284
if sensor != nil {
282285
sensor = nil
283286
}
284-
muSensor.Unlock()
287+
}
288+
289+
// ShutdownCollector cleans up the collector and sensor reference.
290+
// It will also reset the singleton as the next time that instana.InitCollector API is called,
291+
// collector and sensor will be reinitialized.
292+
func ShutdownCollector() {
293+
294+
ShutdownSensor()
295+
muc.Lock()
296+
defer muc.Unlock()
297+
c = newNoopCollector()
298+
once = sync.Once{}
285299
}
286300

287301
func newServerlessAgent(serviceName, agentEndpoint, agentKey string,

0 commit comments

Comments
 (0)