github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/profiler/uploader.go (about) 1 package profiler 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 8 "github.com/rs/zerolog" 9 "google.golang.org/api/option" 10 gtransport "google.golang.org/api/transport/grpc" 11 pb "google.golang.org/genproto/googleapis/devtools/cloudprofiler/v2" 12 "google.golang.org/grpc" 13 ) 14 15 const ( 16 apiAddress = "cloudprofiler.googleapis.com:443" 17 scope = "https://www.googleapis.com/auth/monitoring.write" 18 19 maxMsgSize = 1 << 30 // 1GB 20 ) 21 22 type NoopUploader struct{} 23 24 func (u *NoopUploader) Upload(ctx context.Context, filename string, pt pb.ProfileType) error { 25 return nil 26 } 27 28 type Uploader interface { 29 Upload(ctx context.Context, filename string, pt pb.ProfileType) error 30 } 31 32 type Params struct { 33 ProjectID string 34 ChainID string 35 Role string 36 Version string 37 Commit string 38 Instance string 39 } 40 41 type UploaderImpl struct { 42 log zerolog.Logger 43 client pb.ProfilerServiceClient 44 45 ProjectId string 46 Deployment *pb.Deployment 47 } 48 49 func NewUploader(log zerolog.Logger, params Params, opts ...option.ClientOption) (Uploader, error) { 50 log = log.With().Str("component", "profile_uploader").Logger() 51 52 defaultOpts := []option.ClientOption{ 53 option.WithEndpoint(apiAddress), 54 option.WithScopes(scope), 55 option.WithUserAgent("OfflinePprofUploader"), 56 option.WithTelemetryDisabled(), 57 option.WithGRPCDialOption( 58 grpc.WithDefaultCallOptions( 59 grpc.MaxCallSendMsgSize(maxMsgSize), 60 ), 61 ), 62 } 63 opts = append(defaultOpts, opts...) 64 65 connPool, err := gtransport.DialPool( 66 context.Background(), 67 opts..., 68 ) 69 if err != nil { 70 return &NoopUploader{}, fmt.Errorf("failed to create connection pool: %w", err) 71 } 72 73 version := fmt.Sprintf("%s-%s", params.Version, params.Commit) 74 targetName := fmt.Sprintf("%s-%s", params.ChainID, params.Role) 75 deployment := &pb.Deployment{ 76 ProjectId: params.ProjectID, 77 Target: targetName, 78 Labels: map[string]string{ 79 "language": "go", 80 "version": version, 81 "instance": params.Instance, 82 }, 83 } 84 85 u := &UploaderImpl{ 86 log: log, 87 client: pb.NewProfilerServiceClient(connPool), 88 89 ProjectId: params.ProjectID, 90 Deployment: deployment, 91 } 92 93 return u, nil 94 } 95 96 func (u *UploaderImpl) Upload(ctx context.Context, filename string, pt pb.ProfileType) error { 97 profileBytes, err := os.ReadFile(filename) 98 if err != nil { 99 return fmt.Errorf("failed to read profile: %w", err) 100 } 101 102 req := pb.CreateOfflineProfileRequest{ 103 Parent: u.ProjectId, 104 Profile: &pb.Profile{ 105 ProfileType: pt, 106 Deployment: u.Deployment, 107 ProfileBytes: profileBytes, 108 }, 109 } 110 111 resp, err := u.client.CreateOfflineProfile(ctx, &req) 112 if err != nil { 113 return fmt.Errorf("failed to create offline profile: %w", err) 114 } 115 u.log.Info(). 116 Str("file_name", filename). 117 Str("profile_name", resp.GetName()). 118 Int("profile_size", len(profileBytes)). 119 Msg("uploaded profile") 120 return nil 121 }