Skip to content

Commit 1096792

Browse files
authored
Change fileexporter to use the new SharedComponents because of the file (open-telemetry#3201)
Signed-off-by: Bogdan Drutu <[email protected]>
1 parent 613df75 commit 1096792

File tree

7 files changed

+79
-66
lines changed

7 files changed

+79
-66
lines changed

exporter/fileexporter/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package fileexporter
1616

1717
import (
18+
"errors"
19+
1820
"go.opentelemetry.io/collector/config"
1921
)
2022

@@ -30,5 +32,9 @@ var _ config.Exporter = (*Config)(nil)
3032

3133
// Validate checks if the exporter configuration is valid
3234
func (cfg *Config) Validate() error {
35+
if cfg.Path == "" {
36+
return errors.New("path must be non-empty")
37+
}
38+
3339
return nil
3440
}

exporter/fileexporter/config_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ func TestLoadConfig(t *testing.T) {
3333
factory := NewFactory()
3434
factories.Exporters[typeStr] = factory
3535
cfg, err := configtest.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)
36-
37-
require.NoError(t, err)
36+
require.EqualError(t, err, "exporter \"file\" has invalid configuration: path must be non-empty")
3837
require.NotNil(t, cfg)
3938

4039
e0 := cfg.Exporters[config.NewID(typeStr)]

exporter/fileexporter/factory.go

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ package fileexporter
1616

1717
import (
1818
"context"
19-
"os"
2019

2120
"go.opentelemetry.io/collector/component"
2221
"go.opentelemetry.io/collector/config"
2322
"go.opentelemetry.io/collector/exporter/exporterhelper"
23+
"go.opentelemetry.io/collector/internal/sharedcomponent"
2424
)
2525

2626
const (
@@ -46,52 +46,39 @@ func createDefaultConfig() config.Exporter {
4646

4747
func createTracesExporter(
4848
_ context.Context,
49-
_ component.ExporterCreateParams,
49+
params component.ExporterCreateParams,
5050
cfg config.Exporter,
5151
) (component.TracesExporter, error) {
52-
return createExporter(cfg)
52+
fe := exporters.GetOrAdd(cfg, func() component.Component {
53+
return &fileExporter{path: cfg.(*Config).Path}
54+
})
55+
return exporterhelper.NewTracesExporter(cfg, params.Logger, fe.Unwrap().(*fileExporter).ConsumeTraces)
5356
}
5457

5558
func createMetricsExporter(
5659
_ context.Context,
57-
_ component.ExporterCreateParams,
60+
params component.ExporterCreateParams,
5861
cfg config.Exporter,
5962
) (component.MetricsExporter, error) {
60-
return createExporter(cfg)
63+
fe := exporters.GetOrAdd(cfg, func() component.Component {
64+
return &fileExporter{path: cfg.(*Config).Path}
65+
})
66+
return exporterhelper.NewMetricsExporter(cfg, params.Logger, fe.Unwrap().(*fileExporter).ConsumeMetrics)
6167
}
6268

6369
func createLogsExporter(
6470
_ context.Context,
65-
_ component.ExporterCreateParams,
71+
params component.ExporterCreateParams,
6672
cfg config.Exporter,
6773
) (component.LogsExporter, error) {
68-
return createExporter(cfg)
69-
}
70-
71-
func createExporter(config config.Exporter) (*fileExporter, error) {
72-
cfg := config.(*Config)
73-
74-
// There must be one exporter for metrics, traces, and logs. We maintain a
75-
// map of exporters per config.
76-
77-
// Check to see if there is already a exporter for this config.
78-
exporter, ok := exporters[cfg]
79-
80-
if !ok {
81-
file, err := os.OpenFile(cfg.Path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
82-
if err != nil {
83-
return nil, err
84-
}
85-
exporter = &fileExporter{file: file}
86-
87-
// Remember the receiver in the map
88-
exporters[cfg] = exporter
89-
}
90-
return exporter, nil
74+
fe := exporters.GetOrAdd(cfg, func() component.Component {
75+
return &fileExporter{path: cfg.(*Config).Path}
76+
})
77+
return exporterhelper.NewLogsExporter(cfg, params.Logger, fe.Unwrap().(*fileExporter).ConsumeLogs)
9178
}
9279

9380
// This is the map of already created File exporters for particular configurations.
9481
// We maintain this map because the Factory is asked trace and metric receivers separately
9582
// when it gets CreateTracesReceiver() and CreateMetricsReceiver() but they must not
9683
// create separate objects, they must use one Receiver object per configuration.
97-
var exporters = map[*Config]*fileExporter{}
84+
var exporters = sharedcomponent.NewSharedComponents()

exporter/fileexporter/factory_test.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ func TestCreateMetricsExporter(t *testing.T) {
3838
context.Background(),
3939
component.ExporterCreateParams{Logger: zap.NewNop()},
4040
cfg)
41-
assert.Error(t, err)
42-
require.Nil(t, exp)
41+
assert.NoError(t, err)
42+
require.NotNil(t, exp)
4343
}
4444

4545
func TestCreateTracesExporter(t *testing.T) {
@@ -48,17 +48,16 @@ func TestCreateTracesExporter(t *testing.T) {
4848
context.Background(),
4949
component.ExporterCreateParams{Logger: zap.NewNop()},
5050
cfg)
51-
assert.Error(t, err)
52-
require.Nil(t, exp)
51+
assert.NoError(t, err)
52+
require.NotNil(t, exp)
5353
}
5454

5555
func TestCreateLogsExporter(t *testing.T) {
5656
cfg := createDefaultConfig()
57-
5857
exp, err := createLogsExporter(
5958
context.Background(),
6059
component.ExporterCreateParams{Logger: zap.NewNop()},
6160
cfg)
62-
assert.Error(t, err)
63-
require.Nil(t, exp)
61+
assert.NoError(t, err)
62+
require.NotNil(t, exp)
6463
}

exporter/fileexporter/file_exporter.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package fileexporter
1717
import (
1818
"context"
1919
"io"
20+
"os"
2021
"sync"
2122

2223
"github.com/gogo/protobuf/jsonpb"
@@ -34,6 +35,7 @@ var marshaler = &jsonpb.Marshaler{}
3435
// fileExporter is the implementation of file exporter that writes telemetry data to a file
3536
// in Protobuf-JSON format.
3637
type fileExporter struct {
38+
path string
3739
file io.WriteCloser
3840
mutex sync.Mutex
3941
}
@@ -68,7 +70,9 @@ func exportMessageAsLine(e *fileExporter, message proto.Message) error {
6870
}
6971

7072
func (e *fileExporter) Start(context.Context, component.Host) error {
71-
return nil
73+
var err error
74+
e.file, err = os.OpenFile(e.path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
75+
return err
7276
}
7377

7478
// Shutdown stops the exporter and is invoked during shutdown.

exporter/fileexporter/file_exporter_test.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
package fileexporter
1515

1616
import (
17+
"bytes"
1718
"context"
19+
"io/ioutil"
20+
"os"
1821
"testing"
1922

2023
"github.com/gogo/protobuf/jsonpb"
@@ -31,8 +34,7 @@ import (
3134
)
3235

3336
func TestFileTracesExporter(t *testing.T) {
34-
mf := &testutil.LimitedWriter{}
35-
fe := &fileExporter{file: mf}
37+
fe := &fileExporter{path: tempFileName(t)}
3638
require.NotNil(t, fe)
3739

3840
td := testdata.GenerateTracesTwoSpansSameResource()
@@ -42,7 +44,9 @@ func TestFileTracesExporter(t *testing.T) {
4244

4345
var unmarshaler = &jsonpb.Unmarshaler{}
4446
got := &collectortrace.ExportTraceServiceRequest{}
45-
assert.NoError(t, unmarshaler.Unmarshal(mf, got))
47+
buf, err := ioutil.ReadFile(fe.path)
48+
assert.NoError(t, err)
49+
assert.NoError(t, unmarshaler.Unmarshal(bytes.NewReader(buf), got))
4650
assert.EqualValues(t, internal.TracesToOtlp(td.InternalRep()), got)
4751
}
4852

@@ -54,14 +58,13 @@ func TestFileTracesExporterError(t *testing.T) {
5458
require.NotNil(t, fe)
5559

5660
td := testdata.GenerateTracesTwoSpansSameResource()
57-
assert.NoError(t, fe.Start(context.Background(), componenttest.NewNopHost()))
61+
// Cannot call Start since we inject directly the WriterCloser.
5862
assert.Error(t, fe.ConsumeTraces(context.Background(), td))
5963
assert.NoError(t, fe.Shutdown(context.Background()))
6064
}
6165

6266
func TestFileMetricsExporter(t *testing.T) {
63-
mf := &testutil.LimitedWriter{}
64-
fe := &fileExporter{file: mf}
67+
fe := &fileExporter{path: tempFileName(t)}
6568
require.NotNil(t, fe)
6669

6770
md := testdata.GenerateMetricsTwoMetrics()
@@ -71,7 +74,9 @@ func TestFileMetricsExporter(t *testing.T) {
7174

7275
var unmarshaler = &jsonpb.Unmarshaler{}
7376
got := &collectormetrics.ExportMetricsServiceRequest{}
74-
assert.NoError(t, unmarshaler.Unmarshal(mf, got))
77+
buf, err := ioutil.ReadFile(fe.path)
78+
assert.NoError(t, err)
79+
assert.NoError(t, unmarshaler.Unmarshal(bytes.NewReader(buf), got))
7580
assert.EqualValues(t, internal.MetricsToOtlp(md.InternalRep()), got)
7681
}
7782

@@ -83,14 +88,13 @@ func TestFileMetricsExporterError(t *testing.T) {
8388
require.NotNil(t, fe)
8489

8590
md := testdata.GenerateMetricsTwoMetrics()
86-
assert.NoError(t, fe.Start(context.Background(), componenttest.NewNopHost()))
91+
// Cannot call Start since we inject directly the WriterCloser.
8792
assert.Error(t, fe.ConsumeMetrics(context.Background(), md))
8893
assert.NoError(t, fe.Shutdown(context.Background()))
8994
}
9095

9196
func TestFileLogsExporter(t *testing.T) {
92-
mf := &testutil.LimitedWriter{}
93-
fe := &fileExporter{file: mf}
97+
fe := &fileExporter{path: tempFileName(t)}
9498
require.NotNil(t, fe)
9599

96100
otlp := testdata.GenerateLogsTwoLogRecordsSameResource()
@@ -100,7 +104,9 @@ func TestFileLogsExporter(t *testing.T) {
100104

101105
var unmarshaler = &jsonpb.Unmarshaler{}
102106
got := &collectorlogs.ExportLogsServiceRequest{}
103-
assert.NoError(t, unmarshaler.Unmarshal(mf, got))
107+
buf, err := ioutil.ReadFile(fe.path)
108+
assert.NoError(t, err)
109+
assert.NoError(t, unmarshaler.Unmarshal(bytes.NewReader(buf), got))
104110
assert.EqualValues(t, internal.LogsToOtlp(otlp.InternalRep()), got)
105111
}
106112

@@ -112,7 +118,17 @@ func TestFileLogsExporterErrors(t *testing.T) {
112118
require.NotNil(t, fe)
113119

114120
otlp := testdata.GenerateLogsTwoLogRecordsSameResource()
115-
assert.NoError(t, fe.Start(context.Background(), componenttest.NewNopHost()))
121+
// Cannot call Start since we inject directly the WriterCloser.
116122
assert.Error(t, fe.ConsumeLogs(context.Background(), otlp))
117123
assert.NoError(t, fe.Shutdown(context.Background()))
118124
}
125+
126+
// tempFileName provides a temporary file name for testing.
127+
func tempFileName(t *testing.T) string {
128+
tmpfile, err := ioutil.TempFile("", "*.json")
129+
require.NoError(t, err)
130+
require.NoError(t, tmpfile.Close())
131+
socket := tmpfile.Name()
132+
require.NoError(t, os.Remove(socket))
133+
return socket
134+
}

service/defaultcomponents/default_exporters_test.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,9 @@ func verifyExporterLifecycle(t *testing.T, factory component.ExporterFactory, ge
168168
BuildInfo: component.DefaultBuildInfo(),
169169
}
170170

171-
if getConfigFn == nil {
172-
getConfigFn = factory.CreateDefaultConfig
171+
cfg := factory.CreateDefaultConfig()
172+
if getConfigFn != nil {
173+
cfg = getConfigFn()
173174
}
174175

175176
createFns := []createExporterFn{
@@ -178,19 +179,20 @@ func verifyExporterLifecycle(t *testing.T, factory component.ExporterFactory, ge
178179
wrapCreateMetricsExp(factory),
179180
}
180181

181-
for _, createFn := range createFns {
182-
firstExp, err := createFn(ctx, expCreateParams, getConfigFn())
183-
if errors.Is(err, componenterror.ErrDataTypeIsNotSupported) {
184-
continue
182+
for i := 0; i < 2; i++ {
183+
var exps []component.Exporter
184+
for _, createFn := range createFns {
185+
exp, err := createFn(ctx, expCreateParams, cfg)
186+
if errors.Is(err, componenterror.ErrDataTypeIsNotSupported) {
187+
continue
188+
}
189+
require.NoError(t, err)
190+
require.NoError(t, exp.Start(ctx, host))
191+
exps = append(exps, exp)
192+
}
193+
for _, exp := range exps {
194+
assert.NoError(t, exp.Shutdown(ctx))
185195
}
186-
require.NoError(t, err)
187-
require.NoError(t, firstExp.Start(ctx, host))
188-
require.NoError(t, firstExp.Shutdown(ctx))
189-
190-
secondExp, err := createFn(ctx, expCreateParams, getConfigFn())
191-
require.NoError(t, err)
192-
require.NoError(t, secondExp.Start(ctx, host))
193-
require.NoError(t, secondExp.Shutdown(ctx))
194196
}
195197
}
196198

0 commit comments

Comments
 (0)