diff --git a/components/public-api-server/pkg/apiv1/ide_client.go b/components/public-api-server/pkg/apiv1/ide_client.go index 10cebf4a9af6e4..c48297e999de35 100644 --- a/components/public-api-server/pkg/apiv1/ide_client.go +++ b/components/public-api-server/pkg/apiv1/ide_client.go @@ -9,11 +9,11 @@ import ( "fmt" connect "github.com/bufbuild/connect-go" + "github.com/gitpod-io/gitpod/common-go/log" v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1" "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1/v1connect" protocol "github.com/gitpod-io/gitpod/gitpod-protocol" "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" - "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" ) func NewIDEClientService(pool proxy.ServerConnectionPool) *IDEClientService { @@ -31,8 +31,6 @@ type IDEClientService struct { } func (this *IDEClientService) SendHeartbeat(ctx context.Context, req *connect.Request[v1.SendHeartbeatRequest]) (*connect.Response[v1.SendHeartbeatResponse], error) { - logger := ctxlogrus.Extract(ctx) - conn, err := getConnection(ctx, this.connectionPool) if err != nil { return nil, err @@ -40,12 +38,12 @@ func (this *IDEClientService) SendHeartbeat(ctx context.Context, req *connect.Re workspace, err := conn.GetWorkspace(ctx, req.Msg.GetWorkspaceId()) if err != nil { - logger.WithError(err).Error("Failed to get workspace.") + log.Extract(ctx).WithError(err).Error("Failed to get workspace.") return nil, proxy.ConvertError(err) } if workspace.LatestInstance == nil { - logger.WithError(err).Error("Failed to get latest instance.") + log.Extract(ctx).WithError(err).Error("Failed to get latest instance.") return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("instance not found")) } @@ -61,8 +59,6 @@ func (this *IDEClientService) SendHeartbeat(ctx context.Context, req *connect.Re } func (this *IDEClientService) SendDidClose(ctx context.Context, req *connect.Request[v1.SendDidCloseRequest]) (*connect.Response[v1.SendDidCloseResponse], error) { - logger := ctxlogrus.Extract(ctx) - conn, err := getConnection(ctx, this.connectionPool) if err != nil { return nil, err @@ -70,12 +66,12 @@ func (this *IDEClientService) SendDidClose(ctx context.Context, req *connect.Req workspace, err := conn.GetWorkspace(ctx, req.Msg.GetWorkspaceId()) if err != nil { - logger.WithError(err).Error("Failed to get workspace.") + log.Extract(ctx).WithError(err).Error("Failed to get workspace.") return nil, proxy.ConvertError(err) } if workspace.LatestInstance == nil { - logger.WithError(err).Error("Failed to get latest instance.") + log.Extract(ctx).WithError(err).Error("Failed to get latest instance.") return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("instance not found")) } diff --git a/components/public-api-server/pkg/apiv1/identityprovider.go b/components/public-api-server/pkg/apiv1/identityprovider.go index 5e6bdc723a888d..8000c136f39936 100644 --- a/components/public-api-server/pkg/apiv1/identityprovider.go +++ b/components/public-api-server/pkg/apiv1/identityprovider.go @@ -38,7 +38,7 @@ var _ v1connect.IdentityProviderServiceHandler = ((*IdentityProviderService)(nil // GetIDToken implements v1connect.IDPServiceHandler func (srv *IdentityProviderService) GetIDToken(ctx context.Context, req *connect.Request[v1.GetIDTokenRequest]) (*connect.Response[v1.GetIDTokenResponse], error) { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return nil, err } diff --git a/components/public-api-server/pkg/apiv1/oidc.go b/components/public-api-server/pkg/apiv1/oidc.go index 9435e02e37251f..95302b5f62396b 100644 --- a/components/public-api-server/pkg/apiv1/oidc.go +++ b/components/public-api-server/pkg/apiv1/oidc.go @@ -23,6 +23,7 @@ import ( "github.com/gitpod-io/gitpod/public-api-server/pkg/auth" "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" "github.com/google/uuid" + "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "gorm.io/gorm" @@ -48,7 +49,7 @@ type OIDCService struct { } func (s *OIDCService) CreateClientConfig(ctx context.Context, req *connect.Request[v1.CreateClientConfigRequest]) (*connect.Response[v1.CreateClientConfigResponse], error) { - organizationID, err := validateOrganizationID(req.Msg.Config.GetOrganizationId()) + organizationID, err := validateOrganizationID(ctx, req.Msg.Config.GetOrganizationId()) if err != nil { return nil, err } @@ -58,8 +59,6 @@ func (s *OIDCService) CreateClientConfig(ctx context.Context, req *connect.Reque return nil, connect.NewError(connect.CodeInvalidArgument, err) } - logger := log.WithField("organization_id", organizationID.String()) - conn, err := s.getConnection(ctx) if err != nil { return nil, err @@ -75,7 +74,7 @@ func (s *OIDCService) CreateClientConfig(ctx context.Context, req *connect.Reque data, err := db.EncryptJSON(s.cipher, toDbOIDCSpec(oauth2Config, oidcConfig)) if err != nil { - logger.WithError(err).Error("Failed to encrypt oidc client config.") + log.Extract(ctx).WithError(err).Error("Failed to encrypt oidc client config.") return nil, status.Errorf(codes.Internal, "Failed to store OIDC client config.") } @@ -86,15 +85,17 @@ func (s *OIDCService) CreateClientConfig(ctx context.Context, req *connect.Reque Data: data, }) if err != nil { - logger.WithError(err).Error("Failed to store oidc client config in the database.") + log.Extract(ctx).WithError(err).Error("Failed to store oidc client config in the database.") return nil, status.Errorf(codes.Internal, "Failed to store OIDC client config.") } - logger = log.WithField("oidc_client_config_id", created.ID.String()) + log.AddFields(ctx, logrus.Fields{ + "oidcClientConfigId": created.ID.String(), + }) converted, err := dbOIDCClientConfigToAPI(created, s.cipher) if err != nil { - logger.WithError(err).Error("Failed to convert OIDC Client config to response.") + log.Extract(ctx).WithError(err).Error("Failed to convert OIDC Client config to response.") return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("Failed to convert OIDC Client Config %s for Organization %s to API response", created.ID.String(), organizationID.String())) } @@ -104,18 +105,16 @@ func (s *OIDCService) CreateClientConfig(ctx context.Context, req *connect.Reque } func (s *OIDCService) GetClientConfig(ctx context.Context, req *connect.Request[v1.GetClientConfigRequest]) (*connect.Response[v1.GetClientConfigResponse], error) { - organizationID, err := validateOrganizationID(req.Msg.GetOrganizationId()) + organizationID, err := validateOrganizationID(ctx, req.Msg.GetOrganizationId()) if err != nil { return nil, err } - clientConfigID, err := validateOIDCClientConfigID(req.Msg.GetId()) + clientConfigID, err := validateOIDCClientConfigID(ctx, req.Msg.GetId()) if err != nil { return nil, err } - logger := log.WithField("oidc_client_config_id", clientConfigID.String()).WithField("organization_id", organizationID.String()) - conn, err := s.getConnection(ctx) if err != nil { return nil, err @@ -132,13 +131,13 @@ func (s *OIDCService) GetClientConfig(ctx context.Context, req *connect.Request[ return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("OIDC Client Config %s for Organization %s does not exist", clientConfigID.String(), organizationID.String())) } - logger.WithError(err).Error("Failed to delete OIDC Client config.") + log.Extract(ctx).WithError(err).Error("Failed to delete OIDC Client config.") return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("Failed to delete OIDC Client Config %s for Organization %s", clientConfigID.String(), organizationID.String())) } converted, err := dbOIDCClientConfigToAPI(record, s.cipher) if err != nil { - logger.WithError(err).Error("Failed to convert OIDC Client config to response.") + log.Extract(ctx).WithError(err).Error("Failed to convert OIDC Client config to response.") return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("Failed to convert OIDC Client Config %s for Organization %s to API response", clientConfigID.String(), organizationID.String())) } @@ -148,7 +147,7 @@ func (s *OIDCService) GetClientConfig(ctx context.Context, req *connect.Request[ } func (s *OIDCService) ListClientConfigs(ctx context.Context, req *connect.Request[v1.ListClientConfigsRequest]) (*connect.Response[v1.ListClientConfigsResponse], error) { - organizationID, err := validateOrganizationID(req.Msg.GetOrganizationId()) + organizationID, err := validateOrganizationID(ctx, req.Msg.GetOrganizationId()) if err != nil { return nil, err } @@ -194,18 +193,16 @@ func (s *OIDCService) UpdateClientConfig(ctx context.Context, req *connect.Reque } func (s *OIDCService) DeleteClientConfig(ctx context.Context, req *connect.Request[v1.DeleteClientConfigRequest]) (*connect.Response[v1.DeleteClientConfigResponse], error) { - organizationID, err := validateOrganizationID(req.Msg.GetOrganizationId()) + organizationID, err := validateOrganizationID(ctx, req.Msg.GetOrganizationId()) if err != nil { return nil, err } - clientConfigID, err := validateOIDCClientConfigID(req.Msg.GetId()) + clientConfigID, err := validateOIDCClientConfigID(ctx, req.Msg.GetId()) if err != nil { return nil, err } - logger := log.WithField("oidc_client_config_id", clientConfigID.String()).WithField("organization_id", organizationID.String()) - conn, err := s.getConnection(ctx) if err != nil { return nil, err @@ -222,7 +219,7 @@ func (s *OIDCService) DeleteClientConfig(ctx context.Context, req *connect.Reque return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("OIDC Client Config %s for Organization %s does not exist", clientConfigID.String(), organizationID.String())) } - logger.WithError(err).Error("Failed to delete OIDC Client config.") + log.Extract(ctx).WithError(err).Error("Failed to delete OIDC Client config.") return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("Failed to delete OIDC Client Config %s for Organization %s", clientConfigID.String(), organizationID.String())) } @@ -237,7 +234,7 @@ func (s *OIDCService) getConnection(ctx context.Context) (protocol.APIInterface, conn, err := s.connectionPool.Get(ctx, token) if err != nil { - log.Log.WithError(err).Error("Failed to get connection to server.") + log.Extract(ctx).WithError(err).Error("Failed to get connection to server.") return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to establish connection to downstream services. If this issue persists, please contact Gitpod Support.")) } @@ -250,6 +247,10 @@ func (s *OIDCService) getUser(ctx context.Context, conn protocol.APIInterface) ( return nil, uuid.Nil, proxy.ConvertError(err) } + log.AddFields(ctx, logrus.Fields{ + "userId": user.ID, + }) + if !s.isFeatureEnabled(ctx, conn, user) { return nil, uuid.Nil, connect.NewError(connect.CodePermissionDenied, errors.New("This feature is currently in beta. If you would like to be part of the beta, please contact us.")) } @@ -273,7 +274,7 @@ func (s *OIDCService) isFeatureEnabled(ctx context.Context, conn protocol.APIInt teams, err := conn.GetTeams(ctx) if err != nil { - log.WithError(err).Warnf("Failed to retreive Teams for user %s, personal access token feature flag will not evaluate team membership.", user.ID) + log.Extract(ctx).WithError(err).Warnf("Failed to retreive Teams for user %s, personal access token feature flag will not evaluate team membership.", user.ID) teams = nil } for _, team := range teams { diff --git a/components/public-api-server/pkg/apiv1/project.go b/components/public-api-server/pkg/apiv1/project.go index b4badaacc46ef4..bbcd2aeb7a5665 100644 --- a/components/public-api-server/pkg/apiv1/project.go +++ b/components/public-api-server/pkg/apiv1/project.go @@ -145,7 +145,7 @@ func (s *ProjectsService) ListProjects(ctx context.Context, req *connect.Request } func (s *ProjectsService) DeleteProject(ctx context.Context, req *connect.Request[v1.DeleteProjectRequest]) (*connect.Response[v1.DeleteProjectResponse], error) { - projectID, err := validateProjectID(req.Msg.GetProjectId()) + projectID, err := validateProjectID(ctx, req.Msg.GetProjectId()) if err != nil { return nil, err } @@ -171,7 +171,7 @@ func (s *ProjectsService) getConnection(ctx context.Context) (protocol.APIInterf conn, err := s.connectionPool.Get(ctx, token) if err != nil { - log.Log.WithError(err).Error("Failed to get connection to server.") + log.Extract(ctx).WithError(err).Error("Failed to get connection to server.") return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to establish connection to downstream services. If this issue persists, please contact Gitpod Support.")) } diff --git a/components/public-api-server/pkg/apiv1/team.go b/components/public-api-server/pkg/apiv1/team.go index c5b8da21802774..b3a2afd9669846 100644 --- a/components/public-api-server/pkg/apiv1/team.go +++ b/components/public-api-server/pkg/apiv1/team.go @@ -43,13 +43,13 @@ func (s *TeamService) CreateTeam(ctx context.Context, req *connect.Request[v1.Cr created, err := conn.CreateTeam(ctx, req.Msg.GetName()) if err != nil { - log.WithError(err).Error("Failed to create team.") + log.Extract(ctx).Error("Failed to create team.") return nil, proxy.ConvertError(err) } team, err := s.toTeamAPIResponse(ctx, conn, created) if err != nil { - log.WithError(err).Error("Failed to populate team with details.") + log.Extract(ctx).WithError(err).Error("Failed to populate team with details.") return nil, err } @@ -59,7 +59,7 @@ func (s *TeamService) CreateTeam(ctx context.Context, req *connect.Request[v1.Cr } func (s *TeamService) GetTeam(ctx context.Context, req *connect.Request[v1.GetTeamRequest]) (*connect.Response[v1.GetTeamResponse], error) { - teamID, err := validateTeamID(req.Msg.GetTeamId()) + teamID, err := validateTeamID(ctx, req.Msg.GetTeamId()) if err != nil { return nil, err } @@ -92,7 +92,7 @@ func (s *TeamService) ListTeams(ctx context.Context, req *connect.Request[v1.Lis teams, err := conn.GetTeams(ctx) if err != nil { - log.WithError(err).Error("Failed to list teams from server.") + log.Extract(ctx).WithError(err).Error("Failed to list teams from server.") return nil, proxy.ConvertError(err) } @@ -124,7 +124,7 @@ func (s *TeamService) ListTeams(ctx context.Context, req *connect.Request[v1.Lis resultMap := map[string]*v1.Team{} for res := range resultsChan { if res.err != nil { - log.WithError(err).Error("Failed to populate team with details.") + log.Extract(ctx).WithError(err).Error("Failed to populate team with details.") return nil, err } @@ -143,7 +143,7 @@ func (s *TeamService) ListTeams(ctx context.Context, req *connect.Request[v1.Lis } func (s *TeamService) DeleteTeam(ctx context.Context, req *connect.Request[v1.DeleteTeamRequest]) (*connect.Response[v1.DeleteTeamResponse], error) { - teamID, err := validateTeamID(req.Msg.GetTeamId()) + teamID, err := validateTeamID(ctx, req.Msg.GetTeamId()) if err != nil { return nil, err } @@ -178,7 +178,7 @@ func (s *TeamService) JoinTeam(ctx context.Context, req *connect.Request[v1.Join response, err := s.toTeamAPIResponse(ctx, conn, team) if err != nil { - log.WithError(err).Error("Failed to populate team with details.") + log.Extract(ctx).WithError(err).Error("Failed to populate team with details.") return nil, err } @@ -188,7 +188,7 @@ func (s *TeamService) JoinTeam(ctx context.Context, req *connect.Request[v1.Join } func (s *TeamService) ResetTeamInvitation(ctx context.Context, req *connect.Request[v1.ResetTeamInvitationRequest]) (*connect.Response[v1.ResetTeamInvitationResponse], error) { - teamID, err := validateTeamID(req.Msg.GetTeamId()) + teamID, err := validateTeamID(ctx, req.Msg.GetTeamId()) if err != nil { return nil, err } @@ -270,15 +270,16 @@ func (s *TeamService) DeleteTeamMember(ctx context.Context, req *connect.Request } func (s *TeamService) toTeamAPIResponse(ctx context.Context, conn protocol.APIInterface, team *protocol.Team) (*v1.Team, error) { + logger := log.Extract(ctx).WithField("teamId", team.ID) members, err := conn.GetTeamMembers(ctx, team.ID) if err != nil { - log.WithError(err).Error("Failed to get team members.") + logger.WithError(err).Error("Failed to get team members.") return nil, proxy.ConvertError(err) } invite, err := conn.GetGenericInvite(ctx, team.ID) if err != nil { - log.WithError(err).Error("Failed to get generic invite.") + logger.WithError(err).Error("Failed to get generic invite.") return nil, proxy.ConvertError(err) } diff --git a/components/public-api-server/pkg/apiv1/tokens.go b/components/public-api-server/pkg/apiv1/tokens.go index 78d7b18b5b9f65..8a061601274368 100644 --- a/components/public-api-server/pkg/apiv1/tokens.go +++ b/components/public-api-server/pkg/apiv1/tokens.go @@ -23,6 +23,7 @@ import ( "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" "github.com/google/go-cmp/cmp" "github.com/google/uuid" + "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/fieldmaskpb" "google.golang.org/protobuf/types/known/timestamppb" "gorm.io/gorm" @@ -76,7 +77,7 @@ func (s *TokensService) CreatePersonalAccessToken(ctx context.Context, req *conn pat, err := auth.GeneratePersonalAccessToken(s.signer) if err != nil { - log.WithError(err).Errorf("Failed to generate personal access token for user %s", userID.String()) + log.Extract(ctx).WithError(err).Errorf("Failed to generate personal access token for user %s", userID.String()) return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to generate personal access token.")) } @@ -89,7 +90,7 @@ func (s *TokensService) CreatePersonalAccessToken(ctx context.Context, req *conn ExpirationTime: expiry.AsTime().UTC(), }) if err != nil { - log.WithError(err).Errorf("Failed to store personal access token for user %s", userID.String()) + log.Extract(ctx).WithError(err).Errorf("Failed to store personal access token for user %s", userID.String()) return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to store personal access token.")) } @@ -99,7 +100,7 @@ func (s *TokensService) CreatePersonalAccessToken(ctx context.Context, req *conn } func (s *TokensService) GetPersonalAccessToken(ctx context.Context, req *connect.Request[v1.GetPersonalAccessTokenRequest]) (*connect.Response[v1.GetPersonalAccessTokenResponse], error) { - tokenID, err := validatePersonalAccessTokenID(req.Msg.GetId()) + tokenID, err := validatePersonalAccessTokenID(ctx, req.Msg.GetId()) if err != nil { return nil, err } @@ -149,7 +150,7 @@ func (s *TokensService) ListPersonalAccessTokens(ctx context.Context, req *conne } func (s *TokensService) RegeneratePersonalAccessToken(ctx context.Context, req *connect.Request[v1.RegeneratePersonalAccessTokenRequest]) (*connect.Response[v1.RegeneratePersonalAccessTokenResponse], error) { - tokenID, err := validatePersonalAccessTokenID(req.Msg.GetId()) + tokenID, err := validatePersonalAccessTokenID(ctx, req.Msg.GetId()) if err != nil { return nil, err } @@ -170,7 +171,7 @@ func (s *TokensService) RegeneratePersonalAccessToken(ctx context.Context, req * } pat, err := auth.GeneratePersonalAccessToken(s.signer) if err != nil { - log.WithError(err).Errorf("Failed to regenerate personal access token for user %s", userID.String()) + log.Extract(ctx).WithError(err).Errorf("Failed to regenerate personal access token for user %s", userID.String()) return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to regenerate personal access token.")) } @@ -181,7 +182,7 @@ func (s *TokensService) RegeneratePersonalAccessToken(ctx context.Context, req * return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("Personal Access Token with ID %s for User %s does not exist", tokenID.String(), userID.String())) } - log.WithError(err).Errorf("Failed to store personal access token for user %s", userID.String()) + log.Extract(ctx).WithError(err).Errorf("Failed to store personal access token for user %s", userID.String()) return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to store personal access token.")) } @@ -201,7 +202,7 @@ func (s *TokensService) UpdatePersonalAccessToken(ctx context.Context, req *conn tokenReq := req.Msg.GetToken() - tokenID, err := validatePersonalAccessTokenID(tokenReq.GetId()) + tokenID, err := validatePersonalAccessTokenID(ctx, tokenReq.GetId()) if err != nil { return nil, err } @@ -257,7 +258,7 @@ func (s *TokensService) UpdatePersonalAccessToken(ctx context.Context, req *conn return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("Personal Access Token with ID %s for User %s does not exist", tokenID.String(), userID.String())) } - log.WithError(err).Error("Failed to update PAT for user") + log.Extract(ctx).WithError(err).Error("Failed to update PAT for user") return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("Failed to update token (ID %s) for user (ID %s).", tokenID.String(), userID.String())) } @@ -267,7 +268,7 @@ func (s *TokensService) UpdatePersonalAccessToken(ctx context.Context, req *conn } func (s *TokensService) DeletePersonalAccessToken(ctx context.Context, req *connect.Request[v1.DeletePersonalAccessTokenRequest]) (*connect.Response[v1.DeletePersonalAccessTokenResponse], error) { - tokenID, err := validatePersonalAccessTokenID(req.Msg.GetId()) + tokenID, err := validatePersonalAccessTokenID(ctx, req.Msg.GetId()) if err != nil { return nil, err } @@ -288,7 +289,7 @@ func (s *TokensService) DeletePersonalAccessToken(ctx context.Context, req *conn return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("Personal Access Token with ID %s for User %s does not exist", tokenID.String(), userID.String())) } - log.WithError(err).Errorf("failed to delete personal access token (ID: %s) for user %s", tokenID.String(), userID.String()) + log.Extract(ctx).WithError(err).Errorf("failed to delete personal access token (ID: %s) for user %s", tokenID.String(), userID.String()) return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to delete personal access token.")) } @@ -301,6 +302,10 @@ func (s *TokensService) getUser(ctx context.Context, conn protocol.APIInterface) return nil, uuid.Nil, proxy.ConvertError(err) } + log.AddFields(ctx, logrus.Fields{ + "userId": user.ID, + }) + if !s.isFeatureEnabled(ctx, conn, user) { return nil, uuid.Nil, connect.NewError(connect.CodePermissionDenied, errors.New("This feature is currently in beta. If you would like to be part of the beta, please contact us.")) } @@ -324,7 +329,7 @@ func (s *TokensService) isFeatureEnabled(ctx context.Context, conn protocol.APII teams, err := conn.GetTeams(ctx) if err != nil { - log.WithError(err).Warnf("Failed to retreive Teams for user %s, personal access token feature flag will not evaluate team membership.", user.ID) + log.Extract(ctx).WithError(err).Warnf("Failed to retreive Teams for user %s, personal access token feature flag will not evaluate team membership.", user.ID) teams = nil } for _, team := range teams { @@ -344,7 +349,7 @@ func getConnection(ctx context.Context, pool proxy.ServerConnectionPool) (protoc conn, err := pool.Get(ctx, token) if err != nil { - log.Log.WithError(err).Error("Failed to get connection to server.") + log.Extract(ctx).WithError(err).Error("Failed to get connection to server.") return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to establish connection to downstream services. If this issue persists, please contact Gitpod Support.")) } diff --git a/components/public-api-server/pkg/apiv1/user.go b/components/public-api-server/pkg/apiv1/user.go index ac74646af53c5c..0d458076e8663f 100644 --- a/components/public-api-server/pkg/apiv1/user.go +++ b/components/public-api-server/pkg/apiv1/user.go @@ -8,10 +8,12 @@ import ( "context" connect "github.com/bufbuild/connect-go" + "github.com/gitpod-io/gitpod/common-go/log" v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1" "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1/v1connect" protocol "github.com/gitpod-io/gitpod/gitpod-protocol" "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" + "github.com/sirupsen/logrus" ) func NewUserService(pool proxy.ServerConnectionPool) *UserService { @@ -38,6 +40,9 @@ func (s *UserService) GetAuthenticatedUser(ctx context.Context, req *connect.Req if err != nil { return nil, proxy.ConvertError(err) } + log.AddFields(ctx, logrus.Fields{ + "userId": user.ID, + }) response := userToAPIResponse(user) diff --git a/components/public-api-server/pkg/apiv1/validation.go b/components/public-api-server/pkg/apiv1/validation.go index 4d60172195ff97..0f319812c69817 100644 --- a/components/public-api-server/pkg/apiv1/validation.go +++ b/components/public-api-server/pkg/apiv1/validation.go @@ -5,20 +5,26 @@ package apiv1 import ( + "context" "errors" "fmt" "strings" connect "github.com/bufbuild/connect-go" + "github.com/gitpod-io/gitpod/common-go/log" "github.com/gitpod-io/gitpod/common-go/namegen" "github.com/google/uuid" "github.com/relvacode/iso8601" + "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/fieldmaskpb" "google.golang.org/protobuf/types/known/timestamppb" ) -func validateTeamID(id string) (uuid.UUID, error) { +func validateTeamID(ctx context.Context, id string) (uuid.UUID, error) { + log.AddFields(ctx, logrus.Fields{ + "teamId": id, + }) teamID, err := validateUUID(id) if err != nil { return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Team ID must be a valid UUID.")) @@ -43,7 +49,10 @@ func parseGitpodTimestamp(input string) (*timestamppb.Timestamp, error) { return timestamppb.New(parsed), nil } -func validateWorkspaceID(id string) (string, error) { +func validateWorkspaceID(ctx context.Context, id string) (string, error) { + log.AddFields(ctx, logrus.Fields{ + "workspaceId": id, + }) if id == "" { return "", connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Empty workspace id specified")) } @@ -56,7 +65,10 @@ func validateWorkspaceID(id string) (string, error) { return id, nil } -func validateProjectID(id string) (uuid.UUID, error) { +func validateProjectID(ctx context.Context, id string) (uuid.UUID, error) { + log.AddFields(ctx, logrus.Fields{ + "projectId": id, + }) projectID, err := validateUUID(id) if err != nil { return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Project ID must be a valid UUID.")) @@ -65,7 +77,10 @@ func validateProjectID(id string) (uuid.UUID, error) { return projectID, nil } -func validatePersonalAccessTokenID(id string) (uuid.UUID, error) { +func validatePersonalAccessTokenID(ctx context.Context, id string) (uuid.UUID, error) { + log.AddFields(ctx, logrus.Fields{ + "patId": id, + }) tokenID, err := validateUUID(id) if err != nil { return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Token ID must be a valid UUID")) @@ -74,7 +89,8 @@ func validatePersonalAccessTokenID(id string) (uuid.UUID, error) { return tokenID, nil } -func validateOrganizationID(id string) (uuid.UUID, error) { +func validateOrganizationID(ctx context.Context, id string) (uuid.UUID, error) { + log.AddFields(ctx, logrus.Fields{"orgId": id}) organizationID, err := validateUUID(id) if err != nil { return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("OrganizationID must be a valid UUID")) @@ -83,7 +99,8 @@ func validateOrganizationID(id string) (uuid.UUID, error) { return organizationID, nil } -func validateOIDCClientConfigID(id string) (uuid.UUID, error) { +func validateOIDCClientConfigID(ctx context.Context, id string) (uuid.UUID, error) { + log.AddFields(ctx, logrus.Fields{"oidcClientConfigId": id}) oidcClientConfigID, err := validateUUID(id) if err != nil { return uuid.Nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("OIDC Client Config ID must be a valid UUID")) diff --git a/components/public-api-server/pkg/apiv1/workspace.go b/components/public-api-server/pkg/apiv1/workspace.go index 01eb4fcee37064..7f82cc87223d28 100644 --- a/components/public-api-server/pkg/apiv1/workspace.go +++ b/components/public-api-server/pkg/apiv1/workspace.go @@ -14,7 +14,6 @@ import ( "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1/v1connect" protocol "github.com/gitpod-io/gitpod/gitpod-protocol" "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" - "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -31,13 +30,11 @@ type WorkspaceService struct { } func (s *WorkspaceService) GetWorkspace(ctx context.Context, req *connect.Request[v1.GetWorkspaceRequest]) (*connect.Response[v1.GetWorkspaceResponse], error) { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return nil, err } - logger := ctxlogrus.Extract(ctx).WithField("workspace_id", workspaceID) - conn, err := getConnection(ctx, s.connectionPool) if err != nil { return nil, err @@ -45,13 +42,13 @@ func (s *WorkspaceService) GetWorkspace(ctx context.Context, req *connect.Reques workspace, err := conn.GetWorkspace(ctx, workspaceID) if err != nil { - logger.WithError(err).Error("Failed to get workspace.") + log.Extract(ctx).WithError(err).Error("Failed to get workspace.") return nil, proxy.ConvertError(err) } instance, err := convertWorkspaceInstance(workspace.LatestInstance, workspace.Workspace.Shareable) if err != nil { - logger.WithError(err).Error("Failed to convert workspace instance.") + log.Extract(ctx).WithError(err).Error("Failed to convert workspace instance.") instance = &v1.WorkspaceInstance{} } @@ -76,13 +73,11 @@ func (s *WorkspaceService) GetWorkspace(ctx context.Context, req *connect.Reques } func (s *WorkspaceService) StreamWorkspaceStatus(ctx context.Context, req *connect.Request[v1.StreamWorkspaceStatusRequest], stream *connect.ServerStream[v1.StreamWorkspaceStatusResponse]) error { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return err } - logger := ctxlogrus.Extract(ctx).WithField("workspace_id", workspaceID) - conn, err := getConnection(ctx, s.connectionPool) if err != nil { return err @@ -90,25 +85,25 @@ func (s *WorkspaceService) StreamWorkspaceStatus(ctx context.Context, req *conne workspace, err := conn.GetWorkspace(ctx, workspaceID) if err != nil { - logger.WithError(err).Error("Failed to get workspace.") + log.Extract(ctx).WithError(err).Error("Failed to get workspace.") return proxy.ConvertError(err) } if workspace.LatestInstance == nil { - logger.WithError(err).Error("Failed to get latest instance.") + log.Extract(ctx).WithError(err).Error("Failed to get latest instance.") return connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("instance not found")) } ch, err := conn.InstanceUpdates(ctx, workspace.LatestInstance.ID) if err != nil { - logger.WithError(err).Error("Failed to get workspace instance updates.") + log.Extract(ctx).WithError(err).Error("Failed to get workspace instance updates.") return proxy.ConvertError(err) } for update := range ch { instance, err := convertWorkspaceInstance(update, workspace.Workspace.Shareable) if err != nil { - logger.WithError(err).Error("Failed to convert workspace instance.") + log.Extract(ctx).WithError(err).Error("Failed to convert workspace instance.") return proxy.ConvertError(err) } err = stream.Send(&v1.StreamWorkspaceStatusResponse{ @@ -117,7 +112,7 @@ func (s *WorkspaceService) StreamWorkspaceStatus(ctx context.Context, req *conne }, }) if err != nil { - logger.WithError(err).Error("Failed to stream workspace status.") + log.Extract(ctx).WithError(err).Error("Failed to stream workspace status.") return proxy.ConvertError(err) } } @@ -126,12 +121,11 @@ func (s *WorkspaceService) StreamWorkspaceStatus(ctx context.Context, req *conne } func (s *WorkspaceService) GetOwnerToken(ctx context.Context, req *connect.Request[v1.GetOwnerTokenRequest]) (*connect.Response[v1.GetOwnerTokenResponse], error) { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return nil, err } - logger := ctxlogrus.Extract(ctx).WithField("workspace_id", workspaceID) conn, err := getConnection(ctx, s.connectionPool) if err != nil { return nil, err @@ -140,7 +134,7 @@ func (s *WorkspaceService) GetOwnerToken(ctx context.Context, req *connect.Reque ownerToken, err := conn.GetOwnerToken(ctx, workspaceID) if err != nil { - logger.WithError(err).Error("Failed to get owner token.") + log.Extract(ctx).WithError(err).Error("Failed to get owner token.") return nil, proxy.ConvertError(err) } @@ -183,7 +177,7 @@ func (s *WorkspaceService) ListWorkspaces(ctx context.Context, req *connect.Requ } func (s *WorkspaceService) UpdatePort(ctx context.Context, req *connect.Request[v1.UpdatePortRequest]) (*connect.Response[v1.UpdatePortResponse], error) { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return nil, err } @@ -208,7 +202,7 @@ func (s *WorkspaceService) UpdatePort(ctx context.Context, req *connect.Request[ return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("Unknown port policy specified.")) } if err != nil { - log.WithField("workspace_id", workspaceID).Error("Failed to update port") + log.Extract(ctx).Error("Failed to update port") return nil, proxy.ConvertError(err) } @@ -218,7 +212,7 @@ func (s *WorkspaceService) UpdatePort(ctx context.Context, req *connect.Request[ } func (s *WorkspaceService) StopWorkspace(ctx context.Context, req *connect.Request[v1.StopWorkspaceRequest]) (*connect.Response[v1.StopWorkspaceResponse], error) { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return nil, err } @@ -230,7 +224,7 @@ func (s *WorkspaceService) StopWorkspace(ctx context.Context, req *connect.Reque err = conn.StopWorkspace(ctx, workspaceID) if err != nil { - log.WithField("workspace_id", workspaceID).WithError(err).Error("Failed to stop workspace.") + log.Extract(ctx).WithError(err).Error("Failed to stop workspace.") return nil, proxy.ConvertError(err) } @@ -238,7 +232,7 @@ func (s *WorkspaceService) StopWorkspace(ctx context.Context, req *connect.Reque } func (s *WorkspaceService) DeleteWorkspace(ctx context.Context, req *connect.Request[v1.DeleteWorkspaceRequest]) (*connect.Response[v1.DeleteWorkspaceResponse], error) { - workspaceID, err := validateWorkspaceID(req.Msg.GetWorkspaceId()) + workspaceID, err := validateWorkspaceID(ctx, req.Msg.GetWorkspaceId()) if err != nil { return nil, err } @@ -250,7 +244,7 @@ func (s *WorkspaceService) DeleteWorkspace(ctx context.Context, req *connect.Req err = conn.DeleteWorkspace(ctx, workspaceID) if err != nil { - log.WithField("workspace_id", workspaceID).WithError(err).Error("Failed to delete workspace.") + log.Extract(ctx).WithError(err).Error("Failed to delete workspace.") return nil, proxy.ConvertError(err) } diff --git a/components/public-api-server/pkg/server/logs.go b/components/public-api-server/pkg/server/logs.go index 66ee7751872f4f..6a71ccbfa050b4 100644 --- a/components/public-api-server/pkg/server/logs.go +++ b/components/public-api-server/pkg/server/logs.go @@ -7,6 +7,8 @@ package server import ( "context" + "github.com/gitpod-io/gitpod/common-go/log" + "github.com/bufbuild/connect-go" "github.com/sirupsen/logrus" ) @@ -14,42 +16,38 @@ import ( func NewLogInterceptor(entry *logrus.Entry) connect.UnaryInterceptorFunc { interceptor := func(next connect.UnaryFunc) connect.UnaryFunc { return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { - logger := entry. - WithContext(ctx). - WithField("protocol", "connect"). - WithField("procedure", req.Spec().Procedure). - WithField("address", req.Peer().Addr). - WithField("stream_type", streamType(req.Spec().StreamType)) + ctx = log.ToContext(ctx, entry.WithContext(ctx)) - isClient := req.Spec().IsClient - - if isClient { - logger.WithField("headers", req.Header()).Debugf("Starting request for %s", req.Spec().Procedure) - } else { - logger.WithField("headers", req.Header()).Debugf("Handling request for %s", req.Spec().Procedure) - } + log.AddFields(ctx, logrus.Fields{ + "requestProtocol": "connect", + "requestProcedure": req.Spec().Procedure, + "address": req.Peer().Addr, + "requestStreamType": streamType(req.Spec().StreamType), + "requestHeaders": req.Header(), + }) + log.Extract(ctx).Debugf("Handling request for %s", req.Spec().Procedure) resp, err := next(ctx, req) + + // Retrieve the logger from the context again, in case it's been updated. code := codeOf(err) - logger = logger.WithField("code", code) + log.AddFields(ctx, logrus.Fields{"responseCode": code}) if err != nil { - logger = logger.WithError(err) - if isClient { - logger.Errorf("Received response for %s with code %s", req.Spec().Procedure, code) - } else { - logger.Warnf("Completed handling of request for %s with code %s", req.Spec().Procedure, code) - } + log.AddFields(ctx, logrus.Fields{logrus.ErrorKey: err}) } else { - if resp.Any() != nil { - logger = logger.WithField("response", resp.Any()) - } + log.AddFields(ctx, logrus.Fields{"responseBody": resp.Any()}) + } - if isClient { - logger.WithField("response", resp.Any()).Debugf("Received ok response for %s", req.Spec().Procedure) + if req.Spec().IsClient { + if err != nil { + log.Extract(ctx).Errorf("Received response for %s with code %s", req.Spec().Procedure, code) } else { - logger.WithField("response", resp.Any()).Debugf("Completed handling of request for %s with code %s", req.Spec().Procedure, code) + log.Extract(ctx).Infof("Received response for %s with code %s", req.Spec().Procedure, code) } + log.Extract(ctx).Errorf("Received response for %s with code %s", req.Spec().Procedure, code) + } else { + log.Extract(ctx).Warnf("Completed handling of request for %s with code %s", req.Spec().Procedure, code) } return resp, err