in profiler/export/main.go [48:125]
func downloadProfiles(ctx context.Context, w io.Writer, project, pageToken string, pageSize, maxProfiles int) error {
client, err := cloudprofiler.NewExportClient(ctx)
if err != nil {
return err
}
defer client.Close()
log.Printf("Attempting to fetch %v profiles with a pageSize of %v for %v\n", maxProfiles, pageSize, project)
// Initial request for the ListProfiles API
request := &pb.ListProfilesRequest{
Parent: fmt.Sprintf("projects/%s", project),
PageSize: int32(pageSize),
PageToken: pageToken,
}
// create a folder for storing profiles & metadata
profilesDirName := fmt.Sprintf("profiles_%v", time.Now().Unix())
if err := os.Mkdir(profilesDirName, 0750); err != nil {
log.Fatal(err)
}
// create a file for storing profile metadata
metadata, err := os.Create(fmt.Sprintf("%s/metadata.csv", profilesDirName))
if err != nil {
return err
}
defer metadata.Close()
writer := csv.NewWriter(metadata)
defer writer.Flush()
writer.Write([]string{"File", "Name", "ProfileType", "Target", "Duration", "Labels"})
profileCount := 0
// Keep calling ListProfiles API till all profile pages are fetched or max pages reached
profilesIterator := client.ListProfiles(ctx, request)
for {
// Read individual profile - the client will automatically make API calls to fetch next pages
profile, err := profilesIterator.Next()
if err == iterator.Done {
log.Println("Read all available profiles")
break
}
if err != nil {
return fmt.Errorf("error reading profile from response: %w", err)
}
profileCount++
filename := fmt.Sprintf("%s/profile%06d.pb.gz", profilesDirName, profileCount)
err = os.WriteFile(filename, profile.ProfileBytes, 0640)
if err != nil {
return fmt.Errorf("unable to write file %s: %w", filename, err)
}
fmt.Fprintf(w, "deployment target: %v\n", profile.Deployment.Labels)
labelBytes, err := json.Marshal(profile.Labels)
if err != nil {
return err
}
err = writer.Write([]string{filename, profile.Name, profile.Deployment.Target, profile.Duration.String(), string(labelBytes)})
if err != nil {
return err
}
if maxProfiles > 0 && profileCount >= maxProfiles {
fmt.Fprintf(w, "result: %v", ProfilesDownloadedSuccessfully)
break
}
if profilesIterator.PageInfo().Remaining() == 0 {
// This signifies that the client will make a new API call internally
log.Printf("next page token: %v\n", profilesIterator.PageInfo().Token)
}
}
return nil
}