diff --git a/Makefile b/Makefile index acdc5f5..29c9ba7 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,10 @@ test-go: run-go: SERVE_FROM_FS=true cd desktopcollector; go run ./... +.PHONY: run-go-db +run-go-db: + SERVE_FROM_FS=true cd desktopcollector; go run ./... --db /tmp/otel.db + .PHONY: build-js build-js: cd desktopexporter/internal/app; npx esbuild --bundle main.tsx main.css --outdir=../server/static diff --git a/desktopcollector/components.go b/desktopcollector/components.go index fba86e8..5c4ccf2 100644 --- a/desktopcollector/components.go +++ b/desktopcollector/components.go @@ -15,7 +15,7 @@ import ( otlpreceiver "go.opentelemetry.io/collector/receiver/otlpreceiver" ) -func components() (otelcol.Factories, error) { +func components(dbFilename string) (otelcol.Factories, error) { var err error factories := otelcol.Factories{} @@ -36,13 +36,13 @@ func components() (otelcol.Factories, error) { factories.ReceiverModules[otlpreceiver.NewFactory().Type()] = "go.opentelemetry.io/collector/receiver/otlpreceiver v0.107.0" factories.Exporters, err = exporter.MakeFactoryMap( - desktopexporter.NewFactory(), + desktopexporter.NewFactory(dbFilename), ) if err != nil { return otelcol.Factories{}, err } factories.ExporterModules = make(map[component.Type]string, len(factories.Exporters)) - factories.ExporterModules[desktopexporter.NewFactory().Type()] = "github.com/CtrlSpice/otel-desktop-viewer/desktopexporter" + factories.ExporterModules[desktopexporter.NewFactory(dbFilename).Type()] = "github.com/CtrlSpice/otel-desktop-viewer/desktopexporter" factories.Processors, err = processor.MakeFactoryMap( batchprocessor.NewFactory(), diff --git a/desktopcollector/go.mod b/desktopcollector/go.mod index 7a1fe4e..d42bfac 100644 --- a/desktopcollector/go.mod +++ b/desktopcollector/go.mod @@ -20,6 +20,8 @@ require ( golang.org/x/sys v0.24.0 ) +replace github.com/CtrlSpice/otel-desktop-viewer/desktopexporter => ../desktopexporter + require ( github.com/apache/arrow/go/v17 v17.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect diff --git a/desktopcollector/main.go b/desktopcollector/main.go index b05a27e..2575d7f 100644 --- a/desktopcollector/main.go +++ b/desktopcollector/main.go @@ -17,6 +17,8 @@ import ( "go.opentelemetry.io/collector/otelcol" ) +var dbFilenameFlag string + func main() { info := component.BuildInfo{ Command: "otel-desktop-viewer", @@ -26,7 +28,9 @@ func main() { set := otelcol.CollectorSettings{ BuildInfo: info, - Factories: components, + Factories: func() (otelcol.Factories, error){ + return components(dbFilenameFlag) + }, ConfigProviderSettings: otelcol.ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ ProviderFactories: []confmap.ProviderFactory{ @@ -84,5 +88,6 @@ func newCommand(set otelcol.CollectorSettings) *cobra.Command { rootCmd.Flags().IntVar(&grpcPortFlag, "grpc", 4317, "The port number on which we listen for OTLP grpc payloads") rootCmd.Flags().IntVar(&browserPortFlag, "browser", 8000, "The port number where we expose our data") rootCmd.Flags().StringVar(&hostFlag, "host", "localhost", "The host where we expose our all endpoints (OTLP receivers and browser)") + rootCmd.Flags().StringVar(&dbFilenameFlag, "db", "", "The filename for persistent data. If unset, no data is persisted") return rootCmd } \ No newline at end of file diff --git a/desktopexporter/config.go b/desktopexporter/config.go index 736b5d1..6efe278 100644 --- a/desktopexporter/config.go +++ b/desktopexporter/config.go @@ -8,6 +8,9 @@ import ( type Config struct { // Endpoint defines the host and port where we serve our frontend app Endpoint string `mapstructure:"endpoint"` + // DBFilename defines the local filesystem path for persistent database storage. + // If set to "", no data will be stored persistently. + DBFilename string } // Validate checks if the exporter configuration is valid diff --git a/desktopexporter/exporter.go b/desktopexporter/exporter.go index 51b8389..6997263 100644 --- a/desktopexporter/exporter.go +++ b/desktopexporter/exporter.go @@ -20,7 +20,7 @@ type desktopExporter struct { } func newDesktopExporter(cfg *Config) *desktopExporter { - server := server.NewServer(cfg.Endpoint) + server := server.NewServer(cfg.Endpoint, cfg.DBFilename) return &desktopExporter{ server: server, } diff --git a/desktopexporter/factory.go b/desktopexporter/factory.go index 9426427..e99723f 100644 --- a/desktopexporter/factory.go +++ b/desktopexporter/factory.go @@ -17,10 +17,10 @@ const ( ) // Creates a factory for the Desktop Exporter -func NewFactory() exporter.Factory { +func NewFactory(dbFilename string) exporter.Factory { return exporter.NewFactory( metadata.Type, - createDefaultConfig, + createDefaultConfig(dbFilename), exporter.WithTraces(createTracesExporter, metadata.TracesStability), exporter.WithMetrics(createMetricsExporter, metadata.MetricsStability), exporter.WithLogs(createLogsExporter, metadata.LogsStability), @@ -28,9 +28,12 @@ func NewFactory() exporter.Factory { } // Create default configurations -func createDefaultConfig() component.Config { - return &Config{ - Endpoint: defaultEndpoint, +func createDefaultConfig(dbFilename string) func() component.Config { + return func() component.Config { + return &Config{ + Endpoint: defaultEndpoint, + DBFilename: dbFilename, + } } } diff --git a/desktopexporter/internal/server/server.go b/desktopexporter/internal/server/server.go index 1ec25df..41100be 100644 --- a/desktopexporter/internal/server/server.go +++ b/desktopexporter/internal/server/server.go @@ -25,12 +25,12 @@ type Server struct { Store *store.Store } -func NewServer(endpoint string) *Server { +func NewServer(endpoint, dbFilename string) *Server { s := Server{ server: http.Server{ Addr: endpoint, }, - Store: store.NewStore(context.Background()), + Store: store.NewStore(context.Background(), dbFilename), } serveFromFS, err := strconv.ParseBool(os.Getenv("SERVE_FROM_FS")) diff --git a/desktopexporter/internal/server/server_test.go b/desktopexporter/internal/server/server_test.go index efece4d..99a715d 100644 --- a/desktopexporter/internal/server/server_test.go +++ b/desktopexporter/internal/server/server_test.go @@ -16,7 +16,7 @@ import ( ) func setupEmpty() (*httptest.Server, func()) { - server := NewServer("localhost:8000") + server := NewServer("localhost:8000", "") testServer := httptest.NewServer(server.Handler(false)) return testServer, func() { @@ -26,7 +26,7 @@ func setupEmpty() (*httptest.Server, func()) { } func setupWithTrace(t *testing.T) (*httptest.Server, func(*testing.T)) { - server := NewServer("localhost:8000") + server := NewServer("localhost:8000", "") testSpanData := telemetry.SpanData{ TraceID: "1234567890", TraceState: "", diff --git a/desktopexporter/internal/store/store.go b/desktopexporter/internal/store/store.go index 3b294f9..4fa8074 100644 --- a/desktopexporter/internal/store/store.go +++ b/desktopexporter/internal/store/store.go @@ -21,8 +21,8 @@ type Store struct { conn driver.Conn } -func NewStore(ctx context.Context) *Store { - connector, err := duckdb.NewConnector("", nil) +func NewStore(ctx context.Context, dbFilename string) *Store { + connector, err := duckdb.NewConnector(dbFilename, nil) if err != nil { log.Fatalf("could not initialize new connector: %s", err.Error()) }