Download data profil

Dokumen ini menjelaskan cara mendownload data profil ke sistem lokal, dan cara mengambil data profil secara terprogram dengan menggunakan aplikasi Go.

Mendownload profil menggunakan konsol Google Cloud

Untuk mendownload profil yang ditampilkan dalam flame graph, klik Download .

Profiler menggunakan konvensi penamaan berikut untuk file yang didownload:

profiler_[SERVICE_NAME]_[PROFILE_TYPE]_[FROM_DATE]_[TO_DATE]_[ZONE]_[VERSION].pb.gz

Dalam ekspresi ini:

  • SERVICE_NAME berisi pilihan Layanan Anda
  • PROFILE_TYPE berisi pilihan Profile type Anda
  • FROM_DATE dan TO_DATE berisi spesifikasi rentang waktu Anda
  • ZONE berisi pilihan Zona Anda
  • VERSION berisi pilihan Version Anda

Contoh: profiler_docdemo-service_HEAP_2018-04-22T20_25_31Z_2018-05-22T20_25_31Z_us-east1-c.pb.gz

Mendownload profil secara terprogram

Untuk mengambil data profil, gunakan metode API ListProfiles. Contoh program Go berikut menunjukkan penggunaan API ini.

Program contoh membuat folder di direktori tempat program dijalankan, dan menghasilkan sekumpulan file pprof bernomor. Setiap file memiliki konvensi pemberian nama yang mirip dengan profile000042.pb.gz. Setiap direktori berisi data profil dan file metadata - metadata.csv, yang berisi informasi tentang file yang didownload.


// Sample export shows how ListProfiles API can be used to download
// existing pprof profiles for a given project from GCP.
package main

import (
	"bytes"
	"context"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	cloudprofiler "cloud.google.com/go/cloudprofiler/apiv2"
	pb "cloud.google.com/go/cloudprofiler/apiv2/cloudprofilerpb"
	"google.golang.org/api/iterator"
)

var project = flag.String("project", "", "GCP project ID from which profiles should be fetched")
var pageSize = flag.Int("page_size", 100, "Number of profiles fetched per page. Maximum 1000.")
var pageToken = flag.String("page_token", "", "PageToken from a previous ListProfiles call. If empty, the listing will start from the begnning. Invalid page tokens result in error.")
var maxProfiles = flag.Int("max_profiles", 1000, "Maximum number of profiles to fetch across all pages. If this is <= 0, will fetch all available profiles")

const ProfilesDownloadedSuccessfully = "Read max allowed profiles"

// This function reads profiles for a given project and stores them into locally created files.
// The profile metadata gets stored into a 'metdata.csv' file, while the individual pprof files
// are created per profile.
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
}

func main() {
	flag.Parse()
	// validate project ID
	if *project == "" {
		log.Fatalf("No project ID provided, please provide the GCP project ID via '-project' flag")
	}
	var writer bytes.Buffer
	if err := downloadProfiles(context.Background(), &writer, *project, *pageToken, *pageSize, *maxProfiles); err != nil {
		log.Fatal(err)
	}
	log.Println("Finished reading all profiles")
}

Program contoh menerima argumen command line berikut:

  • project: Project tempat profil diambil. Wajib.
  • page_size: Jumlah maksimum profil yang diambil per panggilan API. Nilai maksimum page_size adalah 1.000. Jika tidak ditentukan, kolom ini akan ditetapkan ke 100.
  • page_token: Token string yang dihasilkan oleh pengoperasian program sebelumnya untuk melanjutkan download. Opsional.
  • max_profiles: Jumlah maksimum profil yang akan diambil. Jika bilangan bulat non-positif diberikan, program akan mencoba mengambil semua profil.
    Opsional.

Menjalankan aplikasi contoh

Untuk menjalankan aplikasi contoh, lakukan langkah berikut:

  1. Meng-cloning repository

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
    
  2. Ubah ke direktori yang berisi program contoh:

    cd golang-samples/profiler/export
    
  3. Jalankan program setelah Anda mengganti YOUR_GCP_PROJECT dengan ID project Google Cloud Anda:

    go run main.go -project YOUR_GCP_PROJECT -page_size 1000 -max_profiles 10000
    

Program ini mungkin memerlukan waktu yang cukup lama untuk diselesaikan. Program ini menghasilkan token untuk halaman berikutnya setelah mengambil halaman saat ini. Anda dapat menggunakan token untuk melanjutkan proses jika program terganggu.

Melihat profil yang didownload

Untuk membaca file yang didownload, yang ditulis dalam format buffer protokol serialisasi, gunakan alat pprof open source.