github.com/koko1123/flow-go-1@v0.29.6/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  }