diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index e7123b8710..7fd0bb1828 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -57,6 +57,17 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env file + run: | + echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env + echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env + echo 'SENTRY_AUTH_TOKEN="${{ secrets.SENTRY_AUTH_TOKEN }}"' >> frontend/.env + echo 'SENTRY_ORG="${{ secrets.SENTRY_ORG }}"' >> frontend/.env + echo 'SENTRY_PROJECT_ID="${{ secrets.SENTRY_PROJECT_ID }}"' >> frontend/.env + echo 'SENTRY_DSN="${{ secrets.SENTRY_DSN }}"' >> frontend/.env + echo 'TUNNEL_URL="${{ secrets.TUNNEL_URL }}"' >> frontend/.env + echo 'TUNNEL_DOMAIN="${{ secrets.TUNNEL_DOMAIN }}"' >> frontend/.env + echo 'POSTHOG_KEY="${{ secrets.POSTHOG_KEY }}"' >> frontend/.env - name: Setup golang uses: actions/setup-go@v4 with: diff --git a/Makefile b/Makefile index 2b2e47c9fa..c7dd0e4a9a 100644 --- a/Makefile +++ b/Makefile @@ -98,12 +98,12 @@ build-query-service-static-arm64: # Steps to build static binary of query service for all platforms .PHONY: build-query-service-static-all -build-query-service-static-all: build-query-service-static-amd64 build-query-service-static-arm64 +build-query-service-static-all: build-query-service-static-amd64 build-query-service-static-arm64 build-frontend-static # Steps to build and push docker image of query service .PHONY: build-query-service-amd64 build-push-query-service # Step to build docker image of query service in amd64 (used in build pipeline) -build-query-service-amd64: build-query-service-static-amd64 +build-query-service-amd64: build-query-service-static-amd64 build-frontend-static @echo "------------------" @echo "--> Building query-service docker image for amd64" @echo "------------------" diff --git a/conf/defaults.yaml b/conf/defaults.yaml new file mode 100644 index 0000000000..dd571e89fb --- /dev/null +++ b/conf/defaults.yaml @@ -0,0 +1,11 @@ +##################### SigNoz Configuration Defaults ##################### +# +# Do not modify this file +# + +##################### Web ##################### +web: + # The prefix to serve web on + prefix: / + # The directory containing the static build files. + directory: /etc/signoz/web \ No newline at end of file diff --git a/ee/query-service/Dockerfile b/ee/query-service/Dockerfile index 5c8f2f6f35..ae4b260f9a 100644 --- a/ee/query-service/Dockerfile +++ b/ee/query-service/Dockerfile @@ -23,6 +23,9 @@ COPY pkg/query-service/templates /root/templates # Make query-service executable for non-root users RUN chmod 755 /root /root/query-service +# Copy frontend +COPY frontend/build/ /etc/signoz/web/ + # run the binary ENTRYPOINT ["./query-service"] diff --git a/ee/query-service/app/server.go b/ee/query-service/app/server.go index 938b72b5a3..5f36aaaf66 100644 --- a/ee/query-service/app/server.go +++ b/ee/query-service/app/server.go @@ -32,6 +32,7 @@ import ( baseauth "go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/migrate" v3 "go.signoz.io/signoz/pkg/query-service/model/v3" + "go.signoz.io/signoz/pkg/web" licensepkg "go.signoz.io/signoz/ee/query-service/license" "go.signoz.io/signoz/ee/query-service/usage" @@ -107,7 +108,7 @@ func (s Server) HealthCheckStatus() chan healthcheck.Status { } // NewServer creates and initializes Server -func NewServer(serverOptions *ServerOptions) (*Server, error) { +func NewServer(serverOptions *ServerOptions, web *web.Web) (*Server, error) { modelDao, err := dao.InitDao("sqlite", baseconst.RELATIONAL_DATASOURCE_PATH) if err != nil { @@ -289,7 +290,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) { usageManager: usageManager, } - httpServer, err := s.createPublicServer(apiHandler) + httpServer, err := s.createPublicServer(apiHandler, web) if err != nil { return nil, err @@ -338,7 +339,7 @@ func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server, }, nil } -func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, error) { +func (s *Server) createPublicServer(apiHandler *api.APIHandler, web *web.Web) (*http.Server, error) { r := baseapp.NewRouter() @@ -382,6 +383,11 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e handler = handlers.CompressHandler(handler) + err := web.AddToRouter(r) + if err != nil { + return nil, err + } + return &http.Server{ Handler: handler, }, nil diff --git a/ee/query-service/main.go b/ee/query-service/main.go index a93a034f87..5fbbca1e18 100644 --- a/ee/query-service/main.go +++ b/ee/query-service/main.go @@ -10,13 +10,17 @@ import ( "syscall" "time" + "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" "go.signoz.io/signoz/ee/query-service/app" + signozconfig "go.signoz.io/signoz/pkg/config" + "go.signoz.io/signoz/pkg/confmap/provider/signozenvprovider" "go.signoz.io/signoz/pkg/query-service/auth" baseconst "go.signoz.io/signoz/pkg/query-service/constants" "go.signoz.io/signoz/pkg/query-service/migrate" "go.signoz.io/signoz/pkg/query-service/version" + signozweb "go.signoz.io/signoz/pkg/web" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -131,6 +135,23 @@ func main() { version.PrintVersion() + config, err := signozconfig.New(context.Background(), signozconfig.ProviderSettings{ + ResolverSettings: confmap.ResolverSettings{ + URIs: []string{"signozenv:"}, + ProviderFactories: []confmap.ProviderFactory{ + signozenvprovider.NewFactory(), + }, + }, + }) + if err != nil { + zap.L().Fatal("Failed to create config", zap.Error(err)) + } + + web, err := signozweb.New(zap.L(), config.Web) + if err != nil { + zap.L().Fatal("Failed to create web", zap.Error(err)) + } + serverOptions := &app.ServerOptions{ HTTPHostPort: baseconst.HTTPHostPort, PromConfigPath: promConfigPath, @@ -165,7 +186,7 @@ func main() { zap.L().Info("Migration successful") } - server, err := app.NewServer(serverOptions) + server, err := app.NewServer(serverOptions, web) if err != nil { zap.L().Fatal("Failed to create server", zap.Error(err)) } diff --git a/frontend/package.json b/frontend/package.json index bbfd1c8564..0379ac9bff 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -242,6 +242,7 @@ "xml2js": "0.5.0", "phin": "^3.7.1", "body-parser": "1.20.3", - "http-proxy-middleware": "3.0.3" + "http-proxy-middleware": "3.0.3", + "cross-spawn": "7.0.5" } } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 8f1214a21a..15e4b72c0f 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -6740,21 +6740,10 @@ cross-fetch@3.1.5: dependencies: node-fetch "2.6.7" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@7.0.5, cross-spawn@^6.0.5, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.5.tgz#910aac880ff5243da96b728bc6521a5f6c2f2f82" + integrity sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" @@ -12120,11 +12109,6 @@ nice-color-palettes@^1.0.1: new-array "^1.0.0" xhr-request "^1.0.1" -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" @@ -12682,11 +12666,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" @@ -14758,7 +14737,7 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" -"semver@2 || 3 || 4 || 5", semver@7.3.7, semver@7.5.4, semver@7.x, semver@^5.5.0, semver@^5.6.0, semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: +"semver@2 || 3 || 4 || 5", semver@7.3.7, semver@7.5.4, semver@7.x, semver@^5.6.0, semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -14870,13 +14849,6 @@ shallowequal@^1.1.0: resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -14884,11 +14856,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" @@ -16765,13 +16732,6 @@ which-typed-array@^1.1.9: has-tostringtag "^1.0.0" is-typed-array "^1.1.10" -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" diff --git a/pkg/config/config.go b/pkg/config/config.go index 02cc7c37c2..6d88cacb61 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -3,10 +3,19 @@ package config import ( "context" + signozconfmap "go.signoz.io/signoz/pkg/confmap" "go.signoz.io/signoz/pkg/instrumentation" "go.signoz.io/signoz/pkg/web" ) +// This map contains the default values of all config structs +var ( + defaults = map[string]signozconfmap.Config{ + "instrumentation": &instrumentation.Config{}, + "web": &web.Config{}, + } +) + // Config defines the entire configuration of signoz. type Config struct { Instrumentation instrumentation.Config `mapstructure:"instrumentation"` @@ -21,15 +30,3 @@ func New(ctx context.Context, settings ProviderSettings) (*Config, error) { return provider.Get(ctx) } - -func byName(name string) (any, bool) { - switch name { - case "instrumentation": - return &instrumentation.Config{}, true - case "web": - return &web.Config{}, true - default: - return nil, false - } - -} diff --git a/pkg/config/unmarshaler.go b/pkg/config/unmarshaler.go index 8392f83462..69cec77193 100644 --- a/pkg/config/unmarshaler.go +++ b/pkg/config/unmarshaler.go @@ -4,7 +4,6 @@ import ( "fmt" "go.opentelemetry.io/collector/confmap" - signozconfmap "go.signoz.io/signoz/pkg/confmap" ) // unmarshal converts a confmap.Conf into a Config struct. @@ -19,22 +18,14 @@ func unmarshal(conf *confmap.Conf) (*Config, error) { parsed := make(map[string]any) - for k := range raw { - e, ok := byName(k) - if !ok { - return nil, fmt.Errorf("cannot find config with name %q", k) - } - i, ok := e.(signozconfmap.Config) - if !ok { - return nil, fmt.Errorf("config %q does not implement \"signozconfmap.Config\"", k) - } - + // To help the defaults kick in, we need iterate over the default map instead of the raw values + for k, v := range defaults { sub, err := conf.Sub(k) if err != nil { return nil, fmt.Errorf("cannot read config for %q: %w", k, err) } - d := i.NewWithDefaults() + d := v.NewWithDefaults() if err := sub.Unmarshal(&d); err != nil { return nil, fmt.Errorf("cannot merge config for %q: %w", k, err) } diff --git a/pkg/config/unmarshaler_test.go b/pkg/config/unmarshaler_test.go index 1627bbcf96..651510eba8 100644 --- a/pkg/config/unmarshaler_test.go +++ b/pkg/config/unmarshaler_test.go @@ -9,7 +9,7 @@ import ( "go.signoz.io/signoz/pkg/instrumentation" ) -func TestUnmarshal(t *testing.T) { +func TestUnmarshalForInstrumentation(t *testing.T) { input := confmap.NewFromStringMap( map[string]any{ "instrumentation": map[string]any{ @@ -29,6 +29,5 @@ func TestUnmarshal(t *testing.T) { cfg, err := unmarshal(input) require.NoError(t, err) - assert.Equal(t, expected, cfg) - + assert.Equal(t, expected.Instrumentation, cfg.Instrumentation) }