├── .github └── workflows │ ├── build.yml │ ├── release.yml │ ├── template │ ├── setup-go-template.yaml │ ├── setup-protobuf-template.yaml │ └── setup-ts-template.yaml │ ├── test-go.yml │ ├── test-ts.yml │ └── testing.yml ├── .gitignore ├── Makefile ├── README.md ├── api ├── api.pb.go └── api_grpc.pb.go ├── assets ├── mock-data │ ├── allocs │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.005.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.006.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.007.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.010.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.012.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.013.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.014.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.015.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.016.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.017.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.018.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.019.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.020.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.021.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.022.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.023.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.024.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.025.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.026.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.027.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.028.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.029.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.030.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.031.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.032.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.033.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.034.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.035.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.036.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.037.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.038.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.039.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.040.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.041.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.042.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.043.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.044.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.045.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.046.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.047.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.048.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.049.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.050.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.051.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.052.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.053.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.054.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.055.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.056.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.057.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.058.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.059.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.060.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.061.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.062.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.063.pb.gz │ │ └── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.064.pb.gz │ ├── cpu │ │ ├── pprof.etcd.samples.cpu.001.pb.gz │ │ ├── pprof.etcd.samples.cpu.002.pb.gz │ │ ├── pprof.etcd.samples.cpu.003.pb.gz │ │ ├── pprof.etcd.samples.cpu.004.pb.gz │ │ ├── pprof.etcd.samples.cpu.005.pb.gz │ │ ├── pprof.etcd.samples.cpu.006.pb.gz │ │ ├── pprof.etcd.samples.cpu.007.pb.gz │ │ ├── pprof.etcd.samples.cpu.008.pb.gz │ │ ├── pprof.etcd.samples.cpu.009.pb.gz │ │ ├── pprof.etcd.samples.cpu.010.pb.gz │ │ ├── pprof.etcd.samples.cpu.011.pb.gz │ │ ├── pprof.etcd.samples.cpu.012.pb.gz │ │ ├── pprof.etcd.samples.cpu.013.pb.gz │ │ ├── pprof.etcd.samples.cpu.014.pb.gz │ │ ├── pprof.etcd.samples.cpu.015.pb.gz │ │ ├── pprof.etcd.samples.cpu.016.pb.gz │ │ ├── pprof.etcd.samples.cpu.017.pb.gz │ │ ├── pprof.etcd.samples.cpu.018.pb.gz │ │ ├── pprof.etcd.samples.cpu.019.pb.gz │ │ ├── pprof.etcd.samples.cpu.020.pb.gz │ │ ├── pprof.etcd.samples.cpu.021.pb.gz │ │ ├── pprof.etcd.samples.cpu.022.pb.gz │ │ ├── pprof.etcd.samples.cpu.023.pb.gz │ │ ├── pprof.etcd.samples.cpu.024.pb.gz │ │ ├── pprof.etcd.samples.cpu.025.pb.gz │ │ ├── pprof.etcd.samples.cpu.026.pb.gz │ │ ├── pprof.etcd.samples.cpu.027.pb.gz │ │ ├── pprof.etcd.samples.cpu.028.pb.gz │ │ ├── pprof.etcd.samples.cpu.029.pb.gz │ │ ├── pprof.etcd.samples.cpu.030.pb.gz │ │ ├── pprof.etcd.samples.cpu.031.pb.gz │ │ ├── pprof.etcd.samples.cpu.032.pb.gz │ │ ├── pprof.etcd.samples.cpu.033.pb.gz │ │ ├── pprof.etcd.samples.cpu.034.pb.gz │ │ ├── pprof.etcd.samples.cpu.035.pb.gz │ │ ├── pprof.etcd.samples.cpu.036.pb.gz │ │ ├── pprof.etcd.samples.cpu.037.pb.gz │ │ ├── pprof.etcd.samples.cpu.038.pb.gz │ │ ├── pprof.etcd.samples.cpu.039.pb.gz │ │ ├── pprof.etcd.samples.cpu.040.pb.gz │ │ ├── pprof.etcd.samples.cpu.041.pb.gz │ │ ├── pprof.etcd.samples.cpu.042.pb.gz │ │ ├── pprof.etcd.samples.cpu.043.pb.gz │ │ ├── pprof.etcd.samples.cpu.044.pb.gz │ │ ├── pprof.etcd.samples.cpu.045.pb.gz │ │ ├── pprof.etcd.samples.cpu.046.pb.gz │ │ ├── pprof.etcd.samples.cpu.047.pb.gz │ │ ├── pprof.etcd.samples.cpu.048.pb.gz │ │ ├── pprof.etcd.samples.cpu.049.pb.gz │ │ ├── pprof.etcd.samples.cpu.050.pb.gz │ │ ├── pprof.etcd.samples.cpu.051.pb.gz │ │ ├── pprof.etcd.samples.cpu.052.pb.gz │ │ ├── pprof.etcd.samples.cpu.053.pb.gz │ │ ├── pprof.etcd.samples.cpu.054.pb.gz │ │ ├── pprof.etcd.samples.cpu.055.pb.gz │ │ ├── pprof.etcd.samples.cpu.056.pb.gz │ │ ├── pprof.etcd.samples.cpu.057.pb.gz │ │ ├── pprof.etcd.samples.cpu.058.pb.gz │ │ ├── pprof.etcd.samples.cpu.059.pb.gz │ │ ├── pprof.etcd.samples.cpu.060.pb.gz │ │ ├── pprof.etcd.samples.cpu.061.pb.gz │ │ ├── pprof.etcd.samples.cpu.062.pb.gz │ │ ├── pprof.etcd.samples.cpu.063.pb.gz │ │ └── pprof.etcd.samples.cpu.064.pb.gz │ ├── goroutine │ │ ├── pprof.etcd.goroutine.001.pb.gz │ │ ├── pprof.etcd.goroutine.002.pb.gz │ │ ├── pprof.etcd.goroutine.003.pb.gz │ │ ├── pprof.etcd.goroutine.004.pb.gz │ │ ├── pprof.etcd.goroutine.005.pb.gz │ │ ├── pprof.etcd.goroutine.006.pb.gz │ │ ├── pprof.etcd.goroutine.007.pb.gz │ │ ├── pprof.etcd.goroutine.008.pb.gz │ │ ├── pprof.etcd.goroutine.009.pb.gz │ │ ├── pprof.etcd.goroutine.010.pb.gz │ │ ├── pprof.etcd.goroutine.011.pb.gz │ │ ├── pprof.etcd.goroutine.012.pb.gz │ │ ├── pprof.etcd.goroutine.013.pb.gz │ │ ├── pprof.etcd.goroutine.014.pb.gz │ │ ├── pprof.etcd.goroutine.015.pb.gz │ │ ├── pprof.etcd.goroutine.016.pb.gz │ │ ├── pprof.etcd.goroutine.017.pb.gz │ │ ├── pprof.etcd.goroutine.018.pb.gz │ │ ├── pprof.etcd.goroutine.019.pb.gz │ │ ├── pprof.etcd.goroutine.020.pb.gz │ │ ├── pprof.etcd.goroutine.021.pb.gz │ │ ├── pprof.etcd.goroutine.022.pb.gz │ │ ├── pprof.etcd.goroutine.023.pb.gz │ │ ├── pprof.etcd.goroutine.024.pb.gz │ │ ├── pprof.etcd.goroutine.025.pb.gz │ │ ├── pprof.etcd.goroutine.026.pb.gz │ │ ├── pprof.etcd.goroutine.027.pb.gz │ │ ├── pprof.etcd.goroutine.028.pb.gz │ │ ├── pprof.etcd.goroutine.029.pb.gz │ │ ├── pprof.etcd.goroutine.030.pb.gz │ │ ├── pprof.etcd.goroutine.031.pb.gz │ │ ├── pprof.etcd.goroutine.032.pb.gz │ │ ├── pprof.etcd.goroutine.033.pb.gz │ │ ├── pprof.etcd.goroutine.034.pb.gz │ │ ├── pprof.etcd.goroutine.035.pb.gz │ │ ├── pprof.etcd.goroutine.036.pb.gz │ │ ├── pprof.etcd.goroutine.037.pb.gz │ │ ├── pprof.etcd.goroutine.038.pb.gz │ │ ├── pprof.etcd.goroutine.039.pb.gz │ │ ├── pprof.etcd.goroutine.040.pb.gz │ │ ├── pprof.etcd.goroutine.041.pb.gz │ │ ├── pprof.etcd.goroutine.042.pb.gz │ │ ├── pprof.etcd.goroutine.043.pb.gz │ │ ├── pprof.etcd.goroutine.044.pb.gz │ │ ├── pprof.etcd.goroutine.045.pb.gz │ │ ├── pprof.etcd.goroutine.046.pb.gz │ │ ├── pprof.etcd.goroutine.047.pb.gz │ │ ├── pprof.etcd.goroutine.048.pb.gz │ │ ├── pprof.etcd.goroutine.049.pb.gz │ │ ├── pprof.etcd.goroutine.050.pb.gz │ │ ├── pprof.etcd.goroutine.051.pb.gz │ │ ├── pprof.etcd.goroutine.052.pb.gz │ │ ├── pprof.etcd.goroutine.053.pb.gz │ │ ├── pprof.etcd.goroutine.054.pb.gz │ │ ├── pprof.etcd.goroutine.055.pb.gz │ │ ├── pprof.etcd.goroutine.056.pb.gz │ │ ├── pprof.etcd.goroutine.057.pb.gz │ │ ├── pprof.etcd.goroutine.058.pb.gz │ │ ├── pprof.etcd.goroutine.059.pb.gz │ │ ├── pprof.etcd.goroutine.060.pb.gz │ │ ├── pprof.etcd.goroutine.061.pb.gz │ │ └── pprof.etcd.goroutine.062.pb.gz │ ├── heap │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.005.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.006.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.007.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.010.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.012.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.013.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.014.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.015.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.016.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.017.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.018.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.019.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.020.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.021.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.022.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.023.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.024.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.025.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.026.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.027.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.028.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.029.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.030.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.031.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.032.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.033.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.034.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.035.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.036.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.037.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.038.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.039.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.040.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.041.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.042.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.043.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.044.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.045.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.046.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.047.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.048.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.049.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.050.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.051.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.052.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.053.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.054.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.055.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.056.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.057.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.058.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.059.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.060.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.061.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.062.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.063.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.064.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.065.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.066.pb.gz │ │ ├── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.067.pb.gz │ │ └── pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.068.pb.gz │ └── how-to-generate-mock-data.sh ├── mock_data.go ├── web.go ├── web │ ├── dummy │ └── html.zip └── web_test.go ├── cmd └── live-pprof │ └── live-pprof.go ├── generate.go ├── go.mk ├── go.mod ├── go.sum ├── internal ├── chi │ ├── chi_web_server.go │ ├── chi_web_server_test.go │ └── middleware.go ├── config │ └── live-pprof-config.go ├── echo │ ├── echo_web_server.go │ └── middleware.go ├── general │ └── general_server.go ├── live-pprof.go ├── logging │ └── logging.go ├── metrics │ ├── metrics_server.go │ ├── metrics_type.go │ ├── mock_assets.go │ ├── mock_metrics_server.go │ └── mock_metrics_server_prod.go ├── rpc.go └── util │ └── util.go ├── main.go ├── pkg ├── test_data │ └── html.zip ├── zip.go └── zip_test.go ├── proto └── api.proto ├── tests ├── e2e │ └── run_binary_test.go └── framework │ ├── util.go │ └── util_test.go └── ts ├── .env.development ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── LICENSE ├── Makefile ├── README.md ├── app ├── about │ ├── layout.tsx │ └── page.tsx ├── blog │ ├── layout.tsx │ └── page.tsx ├── docs │ ├── layout.tsx │ └── page.tsx ├── error.tsx ├── layout.tsx ├── page.tsx ├── pricing │ ├── layout.tsx │ └── page.tsx └── providers.tsx ├── components ├── about-modal.tsx ├── all-graphs.tsx ├── chart-option.tsx ├── charts │ ├── basic-graph.tsx │ ├── dark-theme.js │ ├── data-operation.ts │ ├── data-structure.ts │ └── pprof-chart.tsx ├── client │ └── metrics.ts ├── home-menu.tsx ├── hooks │ ├── __test__ │ │ └── set-url.test.tsx │ ├── use-basic-option.tsx │ ├── use-graph-data.tsx │ ├── use-graph-pref-snap.tsx │ ├── use-is-dev.tsx │ ├── use-param-action.tsx │ ├── use-pprof-option.tsx │ ├── use-profile-duration.tsx │ └── use-url.tsx ├── icons.tsx ├── mock-switch.tsx ├── navbar.tsx ├── primitives.ts ├── recorder-button.tsx ├── recorder-time.tsx ├── retained-samples.tsx ├── sample-interval.tsx ├── smooth-switch.tsx ├── state │ ├── emitter.ts │ ├── pref-state.ts │ ├── recorder-state.ts │ └── ui-state.ts ├── theme-switch.tsx ├── url-bar.tsx ├── url-detect.tsx ├── url-popover.tsx ├── util │ ├── prettyTime.js │ └── util.ts └── window-listener.tsx ├── config ├── fonts.ts └── site.ts ├── next.config.js ├── package.json ├── postcss.config.js ├── prettier.config.js ├── public ├── favicon.ico ├── next.svg └── vercel.svg ├── styles └── globals.css ├── tailwind.config.js ├── tsconfig.json ├── types └── index.ts └── vitest.config.mts /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build binary 2 | 3 | on: 4 | # push: 5 | # branches: [ "main" ] 6 | # paths: 7 | # - '**' 8 | # - '!README.md' 9 | # pull_request: 10 | # branches: [ "main" ] 11 | # paths: 12 | # - '**' 13 | # - '!README.md' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | build_binary: 18 | name: Build binary 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - uses: pnpm/action-setup@v4 25 | name: Install pnpm 26 | with: 27 | version: 9 28 | run_install: false 29 | 30 | - name: Install Node.js 31 | uses: actions/setup-node@v4 32 | with: 33 | node-version: 22 34 | cache: 'pnpm' 35 | cache-dependency-path: 'ts/package.json' 36 | 37 | - name: Install ts dependencies 38 | run: cd ts && pnpm install 39 | 40 | - uses: actions/setup-go@v5 41 | with: 42 | go-version: '^1.23' 43 | cache-dependency-path: "go.sum" 44 | 45 | - name: Install Protoc 46 | uses: arduino/setup-protoc@v3 47 | 48 | - name: Build binary 49 | run: make 50 | 51 | - name: Upload 52 | uses: actions/upload-artifact@v4 53 | with: 54 | name: live-pprof 55 | path: build/live-pprof 56 | compression-level: 9 57 | retention-days: 10 -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | testing: 13 | uses: ./.github/workflows/testing.yml 14 | 15 | release: 16 | needs: [ testing ] 17 | name: Release 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - uses: pnpm/action-setup@v4 24 | name: Install pnpm 25 | with: 26 | version: 9 27 | run_install: false 28 | 29 | - name: Install Node.js 30 | uses: actions/setup-node@v4 31 | with: 32 | node-version: 22 33 | cache: 'pnpm' 34 | cache-dependency-path: 'ts/package.json' 35 | 36 | - name: Install ts dependencies 37 | run: cd ts && pnpm install 38 | 39 | - uses: actions/setup-go@v5 40 | with: 41 | go-version: '^1.23' 42 | cache-dependency-path: "go.sum" 43 | 44 | - name: Install Protoc 45 | uses: arduino/setup-protoc@v3 46 | 47 | - name: Build binary 48 | run: make release 49 | 50 | - name: ls ./build 51 | run: ls ./build 52 | 53 | - name: Upload the artifacts 54 | uses: skx/github-action-publish-binaries@release-2.0 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | with: 58 | args: 'build/*.tar.gz build/*.zip' 59 | -------------------------------------------------------------------------------- /.github/workflows/template/setup-go-template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Setup go 3 | on: [ workflow_call ] 4 | 5 | jobs: 6 | setup_go: 7 | name: Setup go 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/setup-go@v5 11 | with: 12 | go-version: '^1.23' 13 | - name: Install protoc-gen-go-grpc 14 | run: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/template/setup-protobuf-template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Setup protobuf 3 | on: [ workflow_call ] 4 | 5 | jobs: 6 | setup_protobuf: 7 | name: Setup protobuf 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: arduino/setup-protoc@v3 11 | name: Install Protoc 12 | -------------------------------------------------------------------------------- /.github/workflows/template/setup-ts-template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Setup TS 3 | on: [ workflow_call ] 4 | 5 | jobs: 6 | setup_ts: 7 | name: Setup TS 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: pnpm/action-setup@v4 11 | name: Install pnpm 12 | with: 13 | version: 9 14 | run_install: false 15 | 16 | - name: Install Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 22 20 | cache: 'pnpm' 21 | 22 | - name: Install dependencies 23 | run: pnpm install 24 | 25 | - name: Install protoc-gen-js 26 | run: pnpm install -g protoc-gen-js 27 | -------------------------------------------------------------------------------- /.github/workflows/test-go.yml: -------------------------------------------------------------------------------- 1 | name: Test go 2 | 3 | on: 4 | # push: 5 | # branches: [ "main" ] 6 | # paths: 7 | # - '**' 8 | # - '!ts/**' 9 | # - '!README.md' 10 | # pull_request: 11 | # branches: [ "main" ] 12 | # paths: 13 | # - '**' 14 | # - '!ts/**' 15 | # - '!README.md' 16 | workflow_dispatch: 17 | 18 | jobs: 19 | test_go: 20 | name: Test go 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v4 25 | 26 | - uses: actions/setup-go@v5 27 | with: 28 | go-version: '^1.23' 29 | cache-dependency-path: "go.sum" 30 | 31 | - name: Install Protoc 32 | uses: arduino/setup-protoc@v3 33 | 34 | - name: Test 35 | run: make -f go.mk build 36 | -------------------------------------------------------------------------------- /.github/workflows/test-ts.yml: -------------------------------------------------------------------------------- 1 | name: Test TS 2 | 3 | on: 4 | # push: 5 | # branches: [ "main" ] 6 | # paths: 7 | # - ts/** 8 | # - proto/** 9 | # - .github/** 10 | # pull_request: 11 | # branches: [ "main" ] 12 | # paths: 13 | # - ts/** 14 | # - proto/** 15 | # - .github/** 16 | workflow_dispatch: 17 | 18 | jobs: 19 | test_ts: 20 | name: Test TS 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v4 25 | 26 | - uses: pnpm/action-setup@v4 27 | name: Install pnpm 28 | with: 29 | version: 9 30 | run_install: false 31 | 32 | - name: Install Node.js 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: 22 36 | cache: 'pnpm' 37 | cache-dependency-path: 'ts/package.json' 38 | 39 | - name: Install ts dependencies 40 | run: cd ts && pnpm install 41 | 42 | - name: Install Protoc 43 | uses: arduino/setup-protoc@v3 44 | 45 | - name: Test 46 | run: cd ts && make 47 | -------------------------------------------------------------------------------- /.github/workflows/testing.yml: -------------------------------------------------------------------------------- 1 | name: Unit testing and E2E testing 2 | 3 | on: 4 | workflow_call: 5 | push: 6 | branches: [ "main" ] 7 | paths: 8 | - '**' 9 | - '!README.md' 10 | pull_request: 11 | branches: [ "main" ] 12 | paths: 13 | - '**' 14 | - '!README.md' 15 | workflow_dispatch: 16 | 17 | jobs: 18 | testing: 19 | name: Unit testing and E2E testing 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | 25 | - uses: pnpm/action-setup@v4 26 | name: Install pnpm 27 | with: 28 | version: 9 29 | run_install: false 30 | 31 | - name: Install Node.js 32 | uses: actions/setup-node@v4 33 | with: 34 | node-version: 22 35 | cache: 'pnpm' 36 | cache-dependency-path: 'ts/package.json' 37 | 38 | - name: Install ts dependencies 39 | run: cd ts && pnpm install 40 | 41 | - uses: actions/setup-go@v5 42 | with: 43 | go-version: '^1.23' 44 | cache-dependency-path: "go.sum" 45 | 46 | - name: Install Protoc 47 | uses: arduino/setup-protoc@v3 48 | 49 | - name: Unit testing 50 | run: make test 51 | 52 | - name: Upload binary 53 | uses: actions/upload-artifact@v4 54 | with: 55 | name: live-pprof 56 | path: build/live-pprof 57 | compression-level: 9 58 | retention-days: 10 59 | 60 | - name: E2E testing 61 | run: make clean test-e2e 62 | 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.idea 2 | **/.vscode 3 | **/.DS_Store 4 | 5 | node_modules 6 | go.work 7 | package.json 8 | pnpm-lock.yaml 9 | live-pprof 10 | assets/web/html/* 11 | build -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GREEN := \033[32m 2 | YELLOW := \033[33m 3 | RED := \033[31m 4 | RESET := \033[0m 5 | 6 | define print_step 7 | @echo "$(GREEN)===== $(1) =====$(RESET)" 8 | endef 9 | 10 | .PHONY: protoc build release test test-e2e build-for-release 11 | 12 | all: build 13 | $(call print_step, Done) 14 | 15 | release: build-for-release 16 | $(call print_step, Done) 17 | 18 | protoc: 19 | $(call print_step, Generating protobuf files) 20 | $(MAKE) -f go.mk protoc 21 | $(MAKE) -C ts protoc 22 | 23 | build: protoc 24 | $(call print_step, Building) 25 | $(MAKE) -C ts build 26 | $(MAKE) copy 27 | $(MAKE) -f go.mk build 28 | 29 | build-for-release: protoc 30 | $(call print_step, Build for releasing) 31 | $(MAKE) -C ts build 32 | $(MAKE) copy 33 | $(MAKE) zip 34 | $(MAKE) -f go.mk build-for-release 35 | 36 | test: build 37 | $(call print_step, Testing) 38 | $(MAKE) -f go.mk test 39 | $(MAKE) -C ts test 40 | 41 | test-e2e: build 42 | $(call print_step, Testing e2e) 43 | $(MAKE) -f go.mk test-e2e 44 | $(MAKE) clean 45 | $(MAKE) protoc build-for-release 46 | $(call print_step, Testing e2e again) 47 | $(MAKE) -f go.mk test-e2e 48 | 49 | clean: 50 | $(call print_step, Cleaning) 51 | $(MAKE) -f go.mk clean 52 | $(MAKE) -C ts clean 53 | @echo "Removing static files from go" 54 | @if [ -d "./assets/web/html" ]; then \ 55 | rm -rf ./assets/web/html; \ 56 | fi 57 | 58 | copy: 59 | $(call print_step, Removing static files) 60 | @if [ -d "./assets/web/html" ]; then \ 61 | rm -rf ./assets/web/html; \ 62 | fi 63 | $(call print_step, Copying static files) 64 | cp -r ts/out assets/web/html 65 | 66 | zip: 67 | $(call print_step, Removing zip) 68 | @if [ -d "rm ./assets/web/html.zip" ]; then \ 69 | rm -rf rm ./assets/web/html.zip; \ 70 | fi 71 | 72 | $(call print_step, Copying zip) 73 | # this won't work as it creates ts/out entry in the .zip: zip -r assets/web/html.zip ts/out/* 74 | cd ts/out && zip -r ../../assets/web/html.zip ./* 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | You don’t want to clutter up your computer with Docker, Prometheus, Grafana or even K8S just to monitor a Go app's heap size, right? 2 | 3 | Use `live-pprof` to Monitor a Go app's performance. It launches in seconds, boosting your local development. 4 | 5 | [![go-recipes](https://raw.githubusercontent.com/nikolaydubina/go-recipes/main/badge.svg?raw=true)](https://github.com/nikolaydubina/go-recipes) 6 | 7 | Xnip2024-09-10_04-58-57 8 | 9 | https://github.com/user-attachments/assets/77bfacd8-1779-4aaf-9758-9604362a1eb5 10 | 11 |
12 | Screenshots 13 |
14 | Heap 15 | CPU 16 | Allocs 17 | Goroutine 18 | Detect Endpoints 19 | Options 20 |
21 | 22 | 23 | ## Install 24 | 25 | ```bash 26 | go install github.com/moderato-app/live-pprof@v1 27 | ``` 28 | 29 | ## Usage 30 | 31 | #### Step 1: setup pprof endpoints 32 | 33 | ```bash 34 | package main 35 | 36 | import ( 37 | "log" 38 | "net/http" 39 | _ "net/http/pprof" 40 | ) 41 | 42 | func main() { 43 | log.Println(http.ListenAndServe("localhost:6060", nil)) 44 | } 45 | ``` 46 | 47 | #### Step 2: monitor the pprof endpoints 48 | 49 | ```bash 50 | live-pprof 6060 51 | # Or: 52 | live-pprof http://localhost:6060/debug/pprof 53 | # Both commands will monitor http://localhost:6060/debug/pprof 54 | ``` 55 | 56 | ## Limitations 57 | * Metrics data is stored in the browser memory and is cleared on page refresh. 58 | * The page slows down as data grows due to charts rendering. 59 | 60 | As you can see, live-pprof is mainly for local development. These limitations mean it’s not a replacement for Prometheus and Grafana. 61 | 62 | ## Credits 63 | 64 | image 65 | 66 | 67 | Thanks to [Golang Weekly](https://golangweekly.com/latest) for the shoutout! 68 | -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.005.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.005.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.006.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.006.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.007.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.007.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.010.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.010.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.012.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.012.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.013.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.013.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.014.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.014.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.015.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.015.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.016.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.016.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.017.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.017.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.018.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.018.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.019.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.019.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.020.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.020.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.021.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.021.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.022.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.022.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.023.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.023.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.024.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.024.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.025.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.025.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.026.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.026.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.027.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.027.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.028.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.028.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.029.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.029.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.030.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.030.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.031.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.031.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.032.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.032.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.033.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.033.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.034.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.034.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.035.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.035.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.036.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.036.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.037.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.037.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.038.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.038.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.039.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.039.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.040.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.040.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.041.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.041.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.042.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.042.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.043.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.043.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.044.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.044.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.045.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.045.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.046.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.046.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.047.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.047.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.048.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.048.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.049.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.049.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.050.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.050.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.051.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.051.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.052.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.052.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.053.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.053.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.054.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.054.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.055.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.055.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.056.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.056.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.057.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.057.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.058.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.058.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.059.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.059.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.060.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.060.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.061.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.061.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.062.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.062.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.063.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.063.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.064.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/allocs/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.064.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.001.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.001.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.002.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.002.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.003.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.003.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.004.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.004.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.005.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.005.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.006.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.006.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.007.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.007.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.008.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.008.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.009.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.009.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.010.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.010.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.011.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.011.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.012.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.012.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.013.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.013.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.014.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.014.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.015.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.015.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.016.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.016.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.017.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.017.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.018.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.018.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.019.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.019.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.020.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.020.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.021.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.021.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.022.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.022.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.023.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.023.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.024.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.024.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.025.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.025.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.026.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.026.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.027.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.027.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.028.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.028.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.029.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.029.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.030.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.030.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.031.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.031.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.032.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.032.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.033.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.033.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.034.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.034.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.035.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.035.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.036.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.036.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.037.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.037.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.038.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.038.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.039.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.039.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.040.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.040.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.041.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.041.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.042.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.042.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.043.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.043.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.044.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.044.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.045.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.045.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.046.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.046.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.047.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.047.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.048.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.048.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.049.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.049.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.050.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.050.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.051.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.051.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.052.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.052.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.053.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.053.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.054.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.054.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.055.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.055.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.056.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.056.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.057.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.057.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.058.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.058.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.059.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.059.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.060.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.060.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.061.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.061.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.062.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.062.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.063.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.063.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/cpu/pprof.etcd.samples.cpu.064.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/cpu/pprof.etcd.samples.cpu.064.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.001.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.001.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.002.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.002.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.003.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.003.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.004.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.004.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.005.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.005.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.006.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.006.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.007.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.007.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.008.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.008.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.009.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.009.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.010.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.010.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.011.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.011.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.012.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.012.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.013.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.013.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.014.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.014.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.015.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.015.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.016.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.016.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.017.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.017.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.018.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.018.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.019.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.019.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.020.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.020.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.021.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.021.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.022.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.022.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.023.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.023.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.024.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.024.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.025.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.025.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.026.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.026.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.027.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.027.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.028.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.028.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.029.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.029.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.030.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.030.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.031.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.031.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.032.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.032.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.033.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.033.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.034.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.034.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.035.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.035.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.036.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.036.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.037.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.037.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.038.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.038.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.039.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.039.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.040.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.040.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.041.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.041.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.042.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.042.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.043.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.043.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.044.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.044.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.045.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.045.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.046.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.046.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.047.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.047.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.048.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.048.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.049.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.049.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.050.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.050.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.051.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.051.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.052.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.052.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.053.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.053.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.054.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.054.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.055.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.055.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.056.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.056.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.057.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.057.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.058.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.058.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.059.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.059.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.060.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.060.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.061.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.061.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/goroutine/pprof.etcd.goroutine.062.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/goroutine/pprof.etcd.goroutine.062.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.005.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.005.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.006.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.006.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.007.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.007.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.010.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.010.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.012.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.012.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.013.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.013.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.014.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.014.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.015.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.015.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.016.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.016.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.017.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.017.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.018.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.018.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.019.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.019.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.020.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.020.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.021.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.021.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.022.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.022.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.023.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.023.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.024.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.024.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.025.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.025.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.026.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.026.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.027.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.027.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.028.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.028.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.029.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.029.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.030.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.030.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.031.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.031.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.032.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.032.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.033.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.033.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.034.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.034.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.035.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.035.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.036.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.036.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.037.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.037.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.038.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.038.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.039.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.039.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.040.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.040.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.041.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.041.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.042.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.042.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.043.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.043.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.044.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.044.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.045.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.045.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.046.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.046.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.047.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.047.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.048.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.048.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.049.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.049.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.050.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.050.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.051.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.051.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.052.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.052.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.053.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.053.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.054.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.054.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.055.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.055.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.056.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.056.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.057.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.057.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.058.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.058.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.059.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.059.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.060.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.060.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.061.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.061.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.062.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.062.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.063.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.063.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.064.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.064.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.065.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.065.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.066.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.066.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.067.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.067.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.068.pb.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/mock-data/heap/pprof.etcd.alloc_objects.alloc_space.inuse_objects.inuse_space.068.pb.gz -------------------------------------------------------------------------------- /assets/mock-data/how-to-generate-mock-data.sh: -------------------------------------------------------------------------------- 1 | rm -rf default.etcd && etcd --enable-pprof 2 | 3 | ./bin/tools/benchmark put --total=190000000 --val-size=10000 4 | 5 | while true ; do go tool pprof -text http://localhost:2379/debug/pprof/profile\?seconds\=1; done 6 | 7 | while true ; do go tool pprof -text http://localhost:2379/debug/pprof/heap && sleep 1 ;done 8 | 9 | 10 | while true ; do go tool pprof -text http://localhost:2379/debug/pprof/allocs && sleep 1 ;done 11 | 12 | while true ; do go tool pprof -text http://localhost:2379/debug/pprof/goroutine && sleep 1 ;done -------------------------------------------------------------------------------- /assets/mock_data.go: -------------------------------------------------------------------------------- 1 | //go:build !prod 2 | 3 | package assets 4 | 5 | import "embed" 6 | 7 | //go:embed mock-data 8 | var MockData embed.FS 9 | -------------------------------------------------------------------------------- /assets/web.go: -------------------------------------------------------------------------------- 1 | package assets 2 | 3 | import "embed" 4 | 5 | // Web The all: prefix (added in Go 1.18) ensures that any files or directories prefixed with . or _ are included: 6 | // 7 | //go:embed all:web 8 | var Web embed.FS 9 | -------------------------------------------------------------------------------- /assets/web/dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/web/dummy -------------------------------------------------------------------------------- /assets/web/html.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/assets/web/html.zip -------------------------------------------------------------------------------- /assets/web_test.go: -------------------------------------------------------------------------------- 1 | package assets 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestZipContent(t *testing.T) { 10 | z, err := Web.Open("web/html.zip") 11 | defer z.Close() 12 | assert.NoError(t, err) 13 | 14 | stat, err := z.Stat() 15 | assert.NoError(t, err) 16 | 17 | assert.Greater(t, stat.Size(), int64(0)) 18 | assert.Equal(t, stat.Name(), "html.zip") 19 | } 20 | -------------------------------------------------------------------------------- /cmd/live-pprof/live-pprof.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/moderato-app/live-pprof/internal" 5 | ) 6 | 7 | func main() { 8 | internal.LivePprof() 9 | } 10 | -------------------------------------------------------------------------------- /generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate protoc --go_out=./api --go_opt=paths=source_relative --go-grpc_out=./api --go-grpc_opt=paths=source_relative --proto_path ../proto ../proto/api.proto 4 | -------------------------------------------------------------------------------- /go.mk: -------------------------------------------------------------------------------- 1 | BINARY_NAME = live-pprof 2 | ENTRY = ./cmd/live-pprof/live-pprof.go 3 | 4 | .PHONY: build 5 | 6 | all: protoc test build 7 | release: protoc test build-for-release 8 | 9 | protoc: 10 | @echo "Generating protobuf files for go" 11 | @if [ ! -d "./api" ]; then \ 12 | mkdir ./api; \ 13 | fi 14 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 15 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 16 | protoc --go_out=./api --go_opt=paths=source_relative --go-grpc_out=./api --go-grpc_opt=paths=source_relative --proto_path ./proto ./proto/api.proto 17 | 18 | build: 19 | @echo "Building go" 20 | go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME} ${ENTRY} 21 | 22 | build-for-release: 23 | @echo "Building go for release" 24 | GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME}-linux-amd64 ${ENTRY}; 25 | GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME}-linux-arm64 ${ENTRY}; 26 | GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME}-darwin-amd64 ${ENTRY}; 27 | GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME}-darwin-arm64 ${ENTRY}; 28 | GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME}-windows-amd64.exe ${ENTRY}; 29 | GOOS=windows GOARCH=arm64 go build -ldflags="-s -w" -tags prod -o build/${BINARY_NAME}-windows-arm64.exe ${ENTRY}; 30 | cd build; \ 31 | tar -zcvf ${BINARY_NAME}-linux-amd64.tar.gz ${BINARY_NAME}-linux-amd64; \ 32 | tar -zcvf ${BINARY_NAME}-linux-arm64.tar.gz ${BINARY_NAME}-linux-arm64; \ 33 | tar -zcvf ${BINARY_NAME}-darwin-amd64.tar.gz ${BINARY_NAME}-darwin-amd64; \ 34 | tar -zcvf ${BINARY_NAME}-darwin-arm64.tar.gz ${BINARY_NAME}-darwin-arm64; \ 35 | zip -r ${BINARY_NAME}-windows-amd64.exe.zip ${BINARY_NAME}-windows-amd64.exe; \ 36 | zip -r ${BINARY_NAME}-windows-arm64.exe.zip ${BINARY_NAME}-windows-arm64.exe; 37 | 38 | test: 39 | @echo "Testing go" 40 | go test ./... 41 | 42 | test-e2e: 43 | @echo "Testing go" 44 | go test ./... -tags e2e -timeout 30s 45 | 46 | clean: 47 | @echo "Cleaning go" 48 | go clean; rm -rf build; rm -rf assets/web/html 49 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/moderato-app/live-pprof 2 | 3 | go 1.23.0 4 | 5 | //replace github.com/moderato-app/pprof => ../../google-pprof 6 | 7 | require ( 8 | github.com/brpaz/echozap v1.1.3 9 | github.com/go-chi/chi/v5 v5.1.0 10 | github.com/go-cmd/cmd v1.4.3 11 | github.com/improbable-eng/grpc-web v0.15.0 12 | github.com/labstack/echo/v4 v4.12.0 13 | github.com/labstack/gommon v0.4.2 14 | github.com/moderato-app/pprof v0.0.0-20240823224210-78ccd2f4d170 15 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c 16 | github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e 17 | github.com/spf13/pflag v1.0.5 18 | github.com/stretchr/testify v1.9.0 19 | go.uber.org/zap v1.27.0 20 | google.golang.org/grpc v1.65.0 21 | google.golang.org/protobuf v1.34.2 22 | ) 23 | 24 | require ( 25 | github.com/Eun/go-convert v1.2.12 // indirect 26 | github.com/Eun/go-doppelgangerreader v0.0.0-20220728163552-459d94705224 // indirect 27 | github.com/Eun/go-hit v0.5.23 // indirect 28 | github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect 29 | github.com/cenkalti/backoff/v4 v4.1.1 // indirect 30 | github.com/davecgh/go-spew v1.1.1 // indirect 31 | github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect 32 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect 33 | github.com/golang/protobuf v1.5.4 // indirect 34 | github.com/google/go-cmp v0.6.0 // indirect 35 | github.com/gookit/color v1.5.4 // indirect 36 | github.com/ianlancetaylor/demangle v0.0.0-20240805132620-81f5be970eca // indirect 37 | github.com/itchyny/gojq v0.12.16 // indirect 38 | github.com/itchyny/timefmt-go v0.1.6 // indirect 39 | github.com/json-iterator/go v1.1.12 // indirect 40 | github.com/k0kubun/pp v3.0.1+incompatible // indirect 41 | github.com/klauspost/compress v1.11.7 // indirect 42 | github.com/lunixbochs/vtclean v1.0.0 // indirect 43 | github.com/mattn/go-colorable v0.1.13 // indirect 44 | github.com/mattn/go-isatty v0.0.20 // indirect 45 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 46 | github.com/modern-go/reflect2 v1.0.2 // indirect 47 | github.com/pmezard/go-difflib v1.0.0 // indirect 48 | github.com/rs/cors v1.7.0 // indirect 49 | github.com/samber/lo v1.47.0 // indirect 50 | github.com/tidwall/pretty v1.2.1 // indirect 51 | github.com/valyala/bytebufferpool v1.0.0 // indirect 52 | github.com/valyala/fasttemplate v1.2.2 // indirect 53 | github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect 54 | go.uber.org/multierr v1.10.0 // indirect 55 | golang.org/x/crypto v0.23.0 // indirect 56 | golang.org/x/net v0.25.0 // indirect 57 | golang.org/x/sys v0.25.0 // indirect 58 | golang.org/x/text v0.16.0 // indirect 59 | golang.org/x/time v0.5.0 // indirect 60 | golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect 61 | google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506 // indirect 62 | gopkg.in/yaml.v3 v3.0.1 // indirect 63 | nhooyr.io/websocket v1.8.6 // indirect 64 | ) 65 | -------------------------------------------------------------------------------- /internal/chi/chi_web_server.go: -------------------------------------------------------------------------------- 1 | package chi 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/fs" 7 | "net/http" 8 | "net/http/pprof" 9 | _ "net/http/pprof" 10 | 11 | "github.com/go-chi/chi/v5" 12 | chiMiddleware "github.com/go-chi/chi/v5/middleware" 13 | "github.com/moderato-app/live-pprof/assets" 14 | "github.com/moderato-app/live-pprof/pkg" 15 | ) 16 | 17 | func WebServer(middlewares ...func(http.Handler) http.Handler) (*chi.Mux, error) { 18 | router := chi.NewRouter() 19 | router.Use( 20 | chiMiddleware.Logger, 21 | chiMiddleware.Recoverer, 22 | ) 23 | 24 | for _, middleware := range middlewares { 25 | router.Use(middleware) 26 | } 27 | 28 | dir, err := staticFS() 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | router.Handle("/debug/pprof", http.RedirectHandler("/debug/pprof/", http.StatusTemporaryRedirect)) 34 | router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 35 | router.HandleFunc("/debug/pprof/profile", pprof.Profile) 36 | router.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 37 | router.HandleFunc("/debug/pprof/trace", pprof.Trace) 38 | router.HandleFunc("/debug/pprof/*", pprof.Index) 39 | 40 | router.Handle("/*", http.FileServer(http.FS(dir))) 41 | 42 | return router, nil 43 | } 44 | 45 | // staticFS use web/html as static files. If web/html does not exist, 46 | // extract web/html.zip into a memory FS 47 | func staticFS() (fs.FS, error) { 48 | _, err := assets.Web.Open("web/html") 49 | 50 | if err != nil { 51 | // There are 2 cases when web/html doesn't exist: 52 | // 1. During development when web/html isn't generated yet. 53 | // 2. When live-pprof is installed using `go install github.com/moderato-app/live-pprof`. 54 | // In these cases, we can use the html.zip files as static content. They may not have the latest code, 55 | // but they'll still work. 56 | if errors.Is(err, fs.ErrNotExist) { 57 | z, err := assets.Web.Open("web/html.zip") 58 | if err != nil { 59 | return nil, fmt.Errorf("failed to open web/html.zip: %w", err) 60 | } 61 | defer z.Close() 62 | 63 | mf, err := pkg.Unzip(z) 64 | if err != nil { 65 | return nil, fmt.Errorf("failed to unzip web/html.zip: %w", err) 66 | } 67 | return mf, nil 68 | } else { 69 | return nil, fmt.Errorf("failed to open web/html: %w", err) 70 | } 71 | } 72 | 73 | dir, err := fs.Sub(assets.Web, "web/html") 74 | if err != nil { 75 | return nil, fmt.Errorf("failed to open web/html: %w", err) 76 | } 77 | return dir, nil 78 | } 79 | -------------------------------------------------------------------------------- /internal/chi/chi_web_server_test.go: -------------------------------------------------------------------------------- 1 | package chi 2 | 3 | import ( 4 | "io" 5 | "io/fs" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | 10 | "github.com/moderato-app/live-pprof/assets" 11 | "github.com/moderato-app/live-pprof/pkg" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestWebServer(t *testing.T) { 17 | chi, err := WebServer() 18 | assert.NoError(t, err) 19 | 20 | ts := httptest.NewServer(chi) 21 | 22 | resp, err := http.Get(ts.URL + "/") 23 | assert.NoError(t, err) 24 | defer resp.Body.Close() 25 | 26 | assert.Equal(t, resp.StatusCode, http.StatusOK) 27 | assert.Contains(t, resp.Header.Get("Content-Type"), "text/html") 28 | 29 | data, err := io.ReadAll(resp.Body) 30 | assert.NoError(t, err) 31 | bodyStr := string(data) 32 | t.Log("body:", bodyStr) 33 | 34 | assert.Contains(t, bodyStr, "Live pprof") 35 | } 36 | 37 | func TestMemFSHTTPServer(t *testing.T) { 38 | z, err := assets.Web.Open("web/html.zip") 39 | assert.NoError(t, err) 40 | defer z.Close() 41 | 42 | assert.NoError(t, err) 43 | 44 | mf, err := pkg.Unzip(z) 45 | assert.NoError(t, err) 46 | 47 | ts := httptest.NewServer(http.FileServer(http.FS(mf))) 48 | 49 | resp, err := http.Get(ts.URL + "/") 50 | assert.NoError(t, err) 51 | defer resp.Body.Close() 52 | 53 | assert.Equal(t, resp.StatusCode, http.StatusOK) 54 | assert.Contains(t, resp.Header.Get("Content-Type"), "text/html") 55 | 56 | data, err := io.ReadAll(resp.Body) 57 | assert.NoError(t, err) 58 | bodyStr := string(data) 59 | t.Log("body:", bodyStr) 60 | 61 | assert.Contains(t, bodyStr, "Live pprof") 62 | } 63 | 64 | func TestFileNotExists(t *testing.T) { 65 | _, err := assets.Web.Open("web/html2") 66 | assert.ErrorIs(t, err, fs.ErrNotExist) 67 | } 68 | -------------------------------------------------------------------------------- /internal/chi/middleware.go: -------------------------------------------------------------------------------- 1 | package chi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/improbable-eng/grpc-web/go/grpcweb" 7 | ) 8 | 9 | func GrpcMiddleware(grpcWeb *grpcweb.WrappedGrpcServer) func(next http.Handler) http.Handler { 10 | return func(next http.Handler) http.Handler { 11 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 12 | if grpcWeb.IsAcceptableGrpcCorsRequest(r) || grpcWeb.IsGrpcWebRequest(r) { 13 | grpcWeb.ServeHTTP(w, r) 14 | return 15 | } 16 | next.ServeHTTP(w, r) 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /internal/config/live-pprof-config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/moderato-app/live-pprof/internal/logging" 8 | 9 | flag "github.com/spf13/pflag" 10 | ) 11 | 12 | type LivePprofConfig struct { 13 | Host string 14 | Port uint 15 | 16 | PprofURL string 17 | NoBrowser bool 18 | } 19 | 20 | func ParseLPFlags() *LivePprofConfig { 21 | config := &LivePprofConfig{} 22 | 23 | help := false 24 | flag.UintVarP(&config.Port, "port", "p", 8300, "port to listen on") 25 | flag.StringVar(&config.Host, "host", "0.0.0.0", "host to listen on") 26 | flag.BoolVarP(&help, "help", "h", false, "help") 27 | 28 | flag.BoolVarP(&config.NoBrowser, "no-browser", "n", false, "don't open browser") 29 | 30 | flag.Parse() 31 | 32 | args := flag.Args() 33 | if len(args) == 1 { 34 | config.PprofURL = args[0] 35 | } else if len(args) > 1 { 36 | _, _ = fmt.Fprintf(os.Stderr, "Expected 0 or 1 arg, but %d were given: %v\n", len(args), args) 37 | config.printHelp() 38 | os.Exit(0) 39 | } 40 | 41 | if help { 42 | config.printHelp() 43 | os.Exit(0) 44 | } 45 | 46 | logging.Sugar.Infow("flags parsed", "config", config) 47 | return config 48 | } 49 | 50 | func (config *LivePprofConfig) printHelp() { 51 | fmt.Println() 52 | fmt.Println("Usage Example:") 53 | fmt.Println(" live-pprof") 54 | fmt.Println(" open the browser and wait for instructions") 55 | fmt.Println() 56 | fmt.Println(" live-pprof 8080") 57 | fmt.Println(" open the browser and start to monitor http://localhost:8080/debug/pprof") 58 | fmt.Println(" equivalent to `live-pprof http://localhost:8080/debug/pprof`") 59 | fmt.Println(" live-pprof localhost:8080") 60 | fmt.Println(" open the browser and start to monitor http://localhost:8080") 61 | fmt.Println(" live-pprof http://localhost:8080") 62 | fmt.Println(" open the browser and start to monitor http://localhost:8080") 63 | fmt.Println(" live-pprof https://example.com/perf") 64 | fmt.Println(" open the browser and start to monitor https://example.com/perf") 65 | fmt.Println() 66 | fmt.Println(" live-pprof -n") 67 | fmt.Println(" don't open the browser") 68 | fmt.Println(" live-pprof --host 192.168.0.200 -port 1800") 69 | fmt.Println(" listen on 192.168.0.200:1800") 70 | fmt.Println() 71 | fmt.Println("Help") 72 | flag.PrintDefaults() 73 | } 74 | -------------------------------------------------------------------------------- /internal/echo/echo_web_server.go: -------------------------------------------------------------------------------- 1 | package echo 2 | 3 | import ( 4 | "io/fs" 5 | "net/http" 6 | 7 | "github.com/moderato-app/live-pprof/assets" 8 | "github.com/moderato-app/live-pprof/internal/logging" 9 | 10 | "github.com/brpaz/echozap" 11 | "github.com/improbable-eng/grpc-web/go/grpcweb" 12 | echo "github.com/labstack/echo/v4" 13 | "github.com/labstack/echo/v4/middleware" 14 | "github.com/labstack/gommon/log" 15 | ) 16 | 17 | func WebServer(g *grpcweb.WrappedGrpcServer) *echo.Echo { 18 | logging.Sugar.Info("initialise web server...") 19 | e := echo.New() 20 | e.Logger.SetLevel(log.DEBUG) 21 | e.HideBanner = true 22 | 23 | e.Use(echozap.ZapLogger(logging.Logger)) 24 | e.Use(middleware.Logger()) 25 | e.Use(middleware.Recover()) 26 | e.Use(grpcMiddleware(g)) 27 | 28 | e.Use(AllowAllCors) 29 | 30 | w, err := fs.Sub(assets.Web, "web/html") 31 | if err != nil { 32 | logging.Sugar.Panic(err) 33 | } 34 | 35 | s := e.Group("/*") 36 | s.Use(middleware.Gzip()) 37 | h := http.FileServer(http.FS(w)) 38 | s.Any("/*", func(c echo.Context) error { 39 | h.ServeHTTP(c.Response(), c.Request()) 40 | return nil 41 | }) 42 | return e 43 | } 44 | -------------------------------------------------------------------------------- /internal/echo/middleware.go: -------------------------------------------------------------------------------- 1 | package echo 2 | 3 | import ( 4 | "github.com/improbable-eng/grpc-web/go/grpcweb" 5 | "github.com/labstack/echo/v4" 6 | "github.com/labstack/echo/v4/middleware" 7 | ) 8 | 9 | var AllowAllCors = middleware.CORSWithConfig(middleware.CORSConfig{ 10 | AllowOrigins: []string{"*"}, 11 | AllowHeaders: []string{"*", "Authorization"}, 12 | AllowMethods: []string{"*"}, 13 | ExposeHeaders: []string{"*"}, 14 | }) 15 | 16 | func grpcMiddleware(grpcWeb *grpcweb.WrappedGrpcServer) echo.MiddlewareFunc { 17 | return func(next echo.HandlerFunc) echo.HandlerFunc { 18 | return func(c echo.Context) (returnErr error) { 19 | if grpcWeb.IsAcceptableGrpcCorsRequest(c.Request()) || grpcWeb.IsGrpcWebRequest(c.Request()) { 20 | grpcWeb.ServeHTTP(c.Response(), c.Request()) 21 | return nil 22 | } else { 23 | return next(c) 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /internal/general/general_server.go: -------------------------------------------------------------------------------- 1 | package general 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "net/http" 7 | "strings" 8 | "sync" 9 | "time" 10 | 11 | "github.com/moderato-app/live-pprof/api" 12 | "github.com/moderato-app/live-pprof/internal/logging" 13 | "github.com/moderato-app/live-pprof/internal/metrics" 14 | ) 15 | 16 | type GeneralServer struct { 17 | api.UnimplementedGeneralServer 18 | } 19 | 20 | func NewGeneralServer() *GeneralServer { 21 | return &GeneralServer{} 22 | } 23 | 24 | func (m *GeneralServer) DetectURL(req *api.DetectURLRequest, stream api.General_DetectURLServer) error { 25 | logging.Sugar.Debug("DetectURL req:", req) 26 | wg := sync.WaitGroup{} 27 | mts := [...]metrics.MetricsType{ 28 | metrics.MetricsTypeHeap, 29 | metrics.MetricsTypeCPU, 30 | metrics.MetricsTypeAllocs, 31 | metrics.MetricsTypeGoroutine, 32 | } 33 | 34 | urls := make([]string, 0, 5) 35 | urls = append(urls, req.Url) 36 | for _, mt := range mts { 37 | url, err := metrics.MetricsURL(true, mt, req.Url, 1) 38 | if err != nil { 39 | logging.Sugar.Error(err) 40 | panic(err) 41 | } 42 | urls = append(urls, url) 43 | } 44 | 45 | for _, url := range urls { 46 | wg.Add(1) 47 | go func(url string) { 48 | defer wg.Done() 49 | ctx, cancel := context.WithTimeout(stream.Context(), 3*time.Second) 50 | defer cancel() 51 | result, err := detect(ctx, url) 52 | var errMsg *string 53 | if err != nil { 54 | msg := err.Error() 55 | errMsg = &msg 56 | } 57 | resp := api.DetectURLResponse{ 58 | Endpoint: url, 59 | HttpResult: result, 60 | Error: errMsg, 61 | } 62 | err = stream.Send(&resp) 63 | if err != nil { 64 | logging.Sugar.Error(err) 65 | } 66 | }(url) 67 | } 68 | wg.Wait() 69 | return nil 70 | } 71 | 72 | func detect(ctx context.Context, url string) (*api.HTTPResult, error) { 73 | client := &http.Client{} 74 | logging.Sugar.Debugf("GET %s", url) 75 | 76 | method := http.MethodGet 77 | 78 | // don't fetch /profile endpoint since only returns data in pb.gz format 79 | if strings.Contains(url, "/profile?seconds=") { 80 | method = http.MethodHead 81 | } 82 | req, err := http.NewRequestWithContext(ctx, method, url, nil) 83 | if err != nil { 84 | return nil, err 85 | } 86 | resp, err := client.Do(req) 87 | if err != nil { 88 | return nil, err 89 | } 90 | defer func() { _ = resp.Body.Close() }() 91 | 92 | data, err := io.ReadAll(resp.Body) 93 | 94 | if resp.StatusCode < 200 || resp.StatusCode > 399 { 95 | logging.Sugar.Info("resp.Body: \n" + string(data)) 96 | } 97 | 98 | bodyStr := string(data) 99 | 100 | return &api.HTTPResult{ 101 | StatusCode: int32(resp.StatusCode), 102 | StatusText: resp.Status, 103 | Body: &bodyStr, 104 | }, nil 105 | } 106 | -------------------------------------------------------------------------------- /internal/live-pprof.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | "strings" 7 | "time" 8 | 9 | "github.com/moderato-app/live-pprof/api" 10 | "github.com/moderato-app/live-pprof/internal/config" 11 | "github.com/moderato-app/live-pprof/internal/general" 12 | "github.com/moderato-app/live-pprof/internal/logging" 13 | "github.com/moderato-app/live-pprof/internal/metrics" 14 | "github.com/moderato-app/live-pprof/internal/util" 15 | 16 | "github.com/pkg/browser" 17 | "google.golang.org/grpc" 18 | ) 19 | 20 | func LivePprof() { 21 | conf := config.ParseLPFlags() 22 | 23 | var opts []grpc.ServerOption 24 | grpcServer := grpc.NewServer(opts...) 25 | 26 | api.RegisterMetricsServer(grpcServer, metrics.NewMetricsServer()) 27 | api.RegisterMockMetricsServer(grpcServer, metrics.NewMockMetricsServer()) 28 | api.RegisterGeneralServer(grpcServer, general.NewGeneralServer()) 29 | 30 | go func() { 31 | time.Sleep(time.Second) 32 | maybeOpenURL(conf) 33 | }() 34 | 35 | StartServeGrpc(grpcServer, conf) 36 | } 37 | 38 | func maybeOpenURL(conf *config.LivePprofConfig) { 39 | goRun := util.IsRunningAsGoRun() 40 | if conf.NoBrowser || goRun { 41 | logging.Sugar.Debugw("will not open the browser", "conf.NoBrowser", conf.NoBrowser, 42 | "IsRunningAsGoRun", goRun) 43 | return 44 | } 45 | u := url.URL{ 46 | Scheme: "http", 47 | Host: strings.Replace(conf.Host, "0.0.0.0", "localhost", 1) + ":" + strconv.Itoa(int(conf.Port)), 48 | } 49 | 50 | params := url.Values{} 51 | if conf.PprofURL != "" { 52 | params.Add("pprof-url", conf.PprofURL) 53 | } 54 | u.RawQuery = params.Encode() 55 | 56 | logging.Sugar.Infof("opening %s in the browser\n", u.String()) 57 | 58 | _ = browser.OpenURL(u.String()) 59 | } 60 | -------------------------------------------------------------------------------- /internal/logging/logging.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "go.uber.org/zap/zapcore" 6 | ) 7 | 8 | func DefaultLogger() *zap.Logger { 9 | cfg := zap.NewProductionConfig() 10 | cfg.Level = zap.NewAtomicLevelAt(zapcore.DebugLevel) 11 | cfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder 12 | //cfg.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder 13 | cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 14 | cfg.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder 15 | cfg.Encoding = "console" 16 | logger, _ := cfg.Build() 17 | return logger 18 | } 19 | 20 | var Logger = DefaultLogger() 21 | var Sugar = Logger.Sugar() 22 | -------------------------------------------------------------------------------- /internal/metrics/metrics_type.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "errors" 5 | "net/url" 6 | "strconv" 7 | ) 8 | 9 | type MetricsType string 10 | 11 | const ( 12 | MetricsTypeHeap = "heap" 13 | MetricsTypeCPU = "profile" 14 | MetricsTypeAllocs = "allocs" 15 | MetricsTypeGoroutine = "goroutine" 16 | ) 17 | 18 | // MetricsURL generates a URL that works with Go's net/http/pprof. 19 | // 20 | // If debug is true, it fetches data in text format(except for MetricsTypeCPU). 21 | // If debug is false, it fetches data in pb.gz format. 22 | func MetricsURL(debug bool, mt MetricsType, urlStr string, profileSeconds uint64) (string, error) { 23 | parse, err := url.Parse(urlStr) 24 | if err != nil { 25 | return "", errors.New("invalid url: " + urlStr) 26 | } 27 | 28 | var p *url.URL 29 | params := url.Values{} 30 | 31 | p = parse.JoinPath(string(mt)) 32 | 33 | if mt == MetricsTypeCPU { 34 | var sec = uint64(1) 35 | if profileSeconds > 1 { 36 | sec = profileSeconds 37 | } 38 | params.Add("seconds", strconv.Itoa(int(sec))) 39 | } else if debug { 40 | params.Add("debug", "1") 41 | } 42 | p.RawQuery = params.Encode() 43 | 44 | return p.String(), nil 45 | } 46 | -------------------------------------------------------------------------------- /internal/metrics/mock_metrics_server.go: -------------------------------------------------------------------------------- 1 | //go:build !prod 2 | 3 | package metrics 4 | 5 | import ( 6 | "context" 7 | 8 | "github.com/moderato-app/live-pprof/api" 9 | "github.com/moderato-app/live-pprof/internal/logging" 10 | ) 11 | 12 | // MockMetricsServer returns mock data instead of real data to save development time 13 | type MockMetricsServer struct { 14 | api.UnimplementedMockMetricsServer 15 | 16 | mockResources *MockAssets 17 | } 18 | 19 | func NewMockMetricsServer() *MockMetricsServer { 20 | return &MockMetricsServer{ 21 | mockResources: newMockAssets(), 22 | } 23 | } 24 | 25 | func (m *MockMetricsServer) HeapMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 26 | logging.Sugar.Debug("HeapMetrics req:", req) 27 | return m.dispatch(req, MetricsTypeHeap) 28 | } 29 | 30 | func (m *MockMetricsServer) CPUMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 31 | logging.Sugar.Debug("CPUMetrics req:", req) 32 | return m.dispatch(req, MetricsTypeCPU) 33 | } 34 | 35 | func (m *MockMetricsServer) AllocsMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 36 | logging.Sugar.Debug("AllocsMetrics req:", req) 37 | return m.dispatch(req, MetricsTypeAllocs) 38 | } 39 | 40 | func (m *MockMetricsServer) GoroutineMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 41 | logging.Sugar.Debug("GoroutineMetrics req:", req) 42 | return m.dispatch(req, MetricsTypeGoroutine) 43 | } 44 | 45 | func (m *MockMetricsServer) dispatch(req *api.GoMetricsRequest, mt MetricsType) (*api.GoMetricsResponse, error) { 46 | _, err := MetricsURL(false, mt, req.Url, req.ProfileSeconds) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | mtr, err := m.mockResources.GetMetrics(mt) 52 | if err != nil { 53 | logging.Sugar.Error(err) 54 | return nil, err 55 | } 56 | resp := toResp(mtr) 57 | 58 | return resp, nil 59 | } 60 | -------------------------------------------------------------------------------- /internal/metrics/mock_metrics_server_prod.go: -------------------------------------------------------------------------------- 1 | //go:build prod 2 | 3 | package metrics 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | 9 | "github.com/moderato-app/live-pprof/api" 10 | "github.com/moderato-app/live-pprof/internal/logging" 11 | ) 12 | 13 | var mockNotAvailableErr = errors.New("mock data is not available for a prod build") 14 | 15 | // MockMetricsServer returns mock data instead of real data to save development time 16 | type MockMetricsServer struct { 17 | api.UnimplementedMockMetricsServer 18 | } 19 | 20 | func NewMockMetricsServer() *MockMetricsServer { 21 | return &MockMetricsServer{} 22 | } 23 | 24 | func (m *MockMetricsServer) HeapMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 25 | logging.Sugar.Debug("HeapMetrics req:", req) 26 | return nil, mockNotAvailableErr 27 | } 28 | 29 | func (m *MockMetricsServer) CPUMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 30 | logging.Sugar.Debug("CPUMetrics req:", req) 31 | return nil, mockNotAvailableErr 32 | } 33 | 34 | func (m *MockMetricsServer) AllocsMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 35 | logging.Sugar.Debug("AllocsMetrics req:", req) 36 | return nil, mockNotAvailableErr 37 | } 38 | 39 | func (m *MockMetricsServer) GoroutineMetrics(_ context.Context, req *api.GoMetricsRequest) (*api.GoMetricsResponse, error) { 40 | logging.Sugar.Debug("GoroutineMetrics req:", req) 41 | return nil, mockNotAvailableErr 42 | } 43 | -------------------------------------------------------------------------------- /internal/rpc.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "net/http" 8 | "os" 9 | "os/signal" 10 | "strings" 11 | "syscall" 12 | "time" 13 | 14 | chi2 "github.com/moderato-app/live-pprof/internal/chi" 15 | "github.com/moderato-app/live-pprof/internal/config" 16 | "github.com/moderato-app/live-pprof/internal/logging" 17 | 18 | "github.com/improbable-eng/grpc-web/go/grpcweb" 19 | "google.golang.org/grpc" 20 | ) 21 | 22 | func StartServeGrpc(gs *grpc.Server, conf *config.LivePprofConfig) { 23 | l, port, err := findPort(conf.Port, conf.Host) 24 | if err != nil { 25 | logging.Sugar.Fatal(err) 26 | } 27 | conf.Port = port 28 | 29 | logging.Sugar.Infof("listening on %s", l.Addr().String()) 30 | addr := fmt.Sprintf("%s:%d", strings.Replace(conf.Host, "0.0.0.0", "localhost", 1), port) 31 | 32 | //goland:noinspection HttpUrlsUsage 33 | httpURL := "http://" + addr 34 | logging.Sugar.Info("click to open: ", httpURL) 35 | 36 | stopChan := make(chan os.Signal, 1) 37 | signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM) 38 | 39 | wrappedGrpc := grpcweb.WrapServer(gs, grpcweb.WithOriginFunc(func(origin string) bool { 40 | return true 41 | })) 42 | s, err := chi2.WebServer(chi2.GrpcMiddleware(wrappedGrpc)) 43 | 44 | if err != nil { 45 | logging.Sugar.Panic("failed to init WebServer", err) 46 | } 47 | 48 | go func() { 49 | if err := http.Serve(l, s); err != nil { 50 | log.Fatalf("failed starting http2 server: %v", err) 51 | } 52 | }() 53 | 54 | <-stopChan 55 | gracefulShutdown(gs) 56 | 57 | } 58 | 59 | func findPort(port uint, host string) (net.Listener, uint, error) { 60 | for { 61 | if port > 65535 || port == 0 { 62 | return nil, 0, fmt.Errorf("port %d is out of range [1, 65535]", port) 63 | } 64 | addr := fmt.Sprintf("%s:%d", host, port) 65 | l, err := net.Listen("tcp", addr) 66 | if err != nil { 67 | // port already in use 68 | if strings.Contains(err.Error(), "bind: address already in use") { 69 | logging.Sugar.Warnf("address %s already in use, will use a port %d", addr, port+1) 70 | port++ 71 | } else { 72 | return nil, 0, err 73 | } 74 | } else { 75 | return l, port, nil 76 | } 77 | } 78 | } 79 | 80 | func gracefulShutdown(s *grpc.Server) { 81 | logging.Sugar.Info("shutting down gRPC server gracefully") 82 | doneChan := make(chan struct{}) 83 | go func() { 84 | s.GracefulStop() 85 | doneChan <- struct{}{} 86 | }() 87 | 88 | t := time.NewTicker(30 * time.Second) 89 | for { 90 | select { 91 | case <-doneChan: 92 | return 93 | case <-t.C: 94 | return 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /internal/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func IsRunningAsGoRun() bool { 10 | execPath, err := os.Executable() 11 | if err != nil { 12 | return false 13 | } 14 | 15 | fmt.Printf("exec path: %s\n", execPath) 16 | // go run 17 | res := strings.Contains(execPath, "go-build") 18 | // GoLand 19 | res = res || strings.Contains(execPath, "go_build") 20 | 21 | return res 22 | } 23 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/moderato-app/live-pprof/internal" 5 | ) 6 | 7 | func main() { 8 | internal.LivePprof() 9 | } 10 | -------------------------------------------------------------------------------- /pkg/test_data/html.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/pkg/test_data/html.zip -------------------------------------------------------------------------------- /pkg/zip.go: -------------------------------------------------------------------------------- 1 | package pkg 2 | 3 | import ( 4 | "archive/zip" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "io/fs" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/psanford/memfs" 13 | ) 14 | 15 | // Unzip extract a zipFile to a memfs.FS 16 | func Unzip(zipFIle fs.File) (*memfs.FS, error) { 17 | 18 | stat, err := zipFIle.Stat() 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | buf := make([]byte, stat.Size()) 24 | read, err := zipFIle.Read(buf) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | if read != int(stat.Size()) { 30 | return nil, fmt.Errorf("expected %d bytes, got %d", stat.Size(), read) 31 | } 32 | 33 | r := bytes.NewReader(buf) 34 | 35 | reader, err := zip.NewReader(r, stat.Size()) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | rootFS := memfs.New() 41 | 42 | err = unzip(reader, rootFS) 43 | if err != nil { 44 | return nil, err 45 | } 46 | return rootFS, nil 47 | } 48 | 49 | // https://stackoverflow.com/a/24792688 50 | // unzip extract a zip file to memfs 51 | func unzip(zipReader *zip.Reader, fs *memfs.FS) error { 52 | 53 | // Closure to address file descriptors issue with all the deferred .Close() methods 54 | extractAndWriteFile := func(f *zip.File) error { 55 | rc, err := f.Open() 56 | if err != nil { 57 | panic(err) 58 | } 59 | defer func() { 60 | if err := rc.Close(); err != nil { 61 | panic(err) 62 | } 63 | }() 64 | 65 | path := f.Name 66 | 67 | //// Check for ZipSlip (Directory traversal) 68 | //if !strings.HasPrefix(path, filepath.Clean("/")+string(os.PathSeparator)) { 69 | // return fmt.Errorf("illegal file path: %s", path) 70 | //} 71 | 72 | if f.FileInfo().IsDir() { 73 | err := fs.MkdirAll(strings.TrimSuffix(path, "/"), f.Mode()) 74 | if err != nil { 75 | panic(err) 76 | } 77 | } else { 78 | err := fs.MkdirAll(filepath.Dir(path), f.Mode()) 79 | if err != nil { 80 | panic(err) 81 | } 82 | 83 | data, err := io.ReadAll(rc) 84 | if err != nil { 85 | panic(err) 86 | 87 | } 88 | err = fs.WriteFile(path, data, 0755) 89 | 90 | if err != nil { 91 | panic(err) 92 | } 93 | } 94 | return nil 95 | } 96 | 97 | for _, f := range zipReader.File { 98 | err := extractAndWriteFile(f) 99 | if err != nil { 100 | panic(err) 101 | } 102 | } 103 | 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /pkg/zip_test.go: -------------------------------------------------------------------------------- 1 | package pkg 2 | 3 | import ( 4 | "embed" 5 | "io" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | //go:embed all:test_data 12 | var TestData embed.FS 13 | 14 | func TestUnzip(t *testing.T) { 15 | z, err := TestData.Open("test_data/html.zip") 16 | defer z.Close() 17 | assert.NoError(t, err) 18 | 19 | fs, err := Unzip(z) 20 | assert.NoError(t, err) 21 | 22 | html, err := fs.Open("index.html") 23 | assert.NoError(t, err) 24 | 25 | stat, err := html.Stat() 26 | assert.NoError(t, err) 27 | 28 | assert.Greater(t, stat.Size(), int64(0)) 29 | all, err := io.ReadAll(html) 30 | assert.NoError(t, err) 31 | 32 | assert.Contains(t, string(all), "Live pprof") 33 | } 34 | -------------------------------------------------------------------------------- /proto/api.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package server; 3 | 4 | option go_package = "github.com/moderato-app/live-pprof/api"; 5 | 6 | service Metrics { 7 | rpc HeapMetrics(GoMetricsRequest) returns (GoMetricsResponse); 8 | rpc CPUMetrics(GoMetricsRequest) returns (GoMetricsResponse); 9 | rpc AllocsMetrics(GoMetricsRequest) returns (GoMetricsResponse); 10 | rpc GoroutineMetrics(GoMetricsRequest) returns (GoMetricsResponse); 11 | } 12 | 13 | // MockMetrics returns mock data instead of real data to save development time 14 | service MockMetrics { 15 | rpc HeapMetrics(GoMetricsRequest) returns (GoMetricsResponse); 16 | rpc CPUMetrics(GoMetricsRequest) returns (GoMetricsResponse); 17 | rpc AllocsMetrics(GoMetricsRequest) returns (GoMetricsResponse); 18 | rpc GoroutineMetrics(GoMetricsRequest) returns (GoMetricsResponse); 19 | } 20 | 21 | service General { 22 | rpc DetectURL(DetectURLRequest) returns (stream DetectURLResponse); 23 | } 24 | 25 | message GoMetricsRequest { 26 | string url = 1; 27 | // cpu profile only 28 | uint64 profile_seconds = 2; 29 | } 30 | 31 | message GoMetricsResponse { 32 | int64 date = 1; 33 | repeated Item items = 2; 34 | int64 total = 3; 35 | } 36 | 37 | message Item { 38 | string func = 1; 39 | string line = 2; 40 | int64 flat = 3 ; 41 | int64 cum = 4; 42 | } 43 | 44 | message DetectURLRequest { 45 | string url = 1; 46 | } 47 | 48 | message DetectURLResponse { 49 | string endpoint = 1; 50 | 51 | optional HTTPResult httpResult = 2; 52 | optional string error = 4; 53 | } 54 | 55 | message HTTPResult{ 56 | int32 statusCode = 1; 57 | string statusText = 2; 58 | optional string body = 3; 59 | } -------------------------------------------------------------------------------- /tests/e2e/run_binary_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package e2e 4 | 5 | import ( 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "testing" 10 | 11 | . "github.com/Eun/go-hit" 12 | "github.com/go-cmd/cmd" 13 | . "github.com/moderato-app/live-pprof/tests/framework" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | //goland:noinspection HttpUrlsUsage 18 | func TestRunBinary(t *testing.T) { 19 | 20 | binary, err := FindBinary(t) 21 | assert.NoError(t, err, "failed to find binary") 22 | 23 | host := "localhost" 24 | port := 12345 25 | 26 | c := cmd.NewCmd(binary, "-n", "--port", strconv.Itoa(port), "--host", host) 27 | 28 | c.Start() 29 | defer c.Stop() 30 | 31 | WaitForRunningOrFail(t, c, true) 32 | 33 | assert.True(t, LogContainsText(c.Status(), "listening on localhost:12345") || 34 | LogContainsText(c.Status(), "listening on 127.0.0.1:12345"), WhatsWrong(c.Status())) 35 | 36 | url := fmt.Sprintf("http://%s:%d", host, port) 37 | 38 | Test(t, 39 | Description("Get home page: "+url), 40 | Get(url), 41 | Expect().Status().Equal(http.StatusOK), 42 | Expect().Body().String().Contains("Live pprof"), 43 | ) 44 | 45 | url = fmt.Sprintf("http://%s:%d/favicon.ico", host, port) 46 | 47 | Test(t, 48 | Description("Get favicon.ico: "+url), 49 | Get(url), 50 | Expect().Status().Equal(http.StatusOK), 51 | Expect().Headers("content-type").First().Contains("image"), 52 | Expect().Body().Bytes().Len().GreaterThan(0), 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /tests/framework/util.go: -------------------------------------------------------------------------------- 1 | package framework 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "os/exec" 9 | "path" 10 | "runtime" 11 | "strings" 12 | "testing" 13 | "time" 14 | 15 | "github.com/go-cmd/cmd" 16 | "github.com/stretchr/testify/assert" 17 | ) 18 | 19 | func FindBinary(t *testing.T) (string, error) { 20 | 21 | binaryName := "live-pprof" 22 | 23 | rootDir := RootDir(t) 24 | fileName := path.Join(rootDir, "build", binaryName) 25 | 26 | _, err := os.Stat(fileName) 27 | 28 | if err != nil { 29 | if os.IsNotExist(err) { 30 | if runtime.GOOS != "linux" && runtime.GOOS != "windows" && runtime.GOOS != "darwin" { 31 | return "", fmt.Errorf("unsupported OS: %s", runtime.GOOS) 32 | } 33 | fileName = path.Join(rootDir, "build", fmt.Sprintf("%s-%s-%s", binaryName, runtime.GOOS, runtime.GOARCH)) 34 | 35 | if runtime.GOOS == "windows" { 36 | fileName += ".exe" 37 | } 38 | if _, err := os.Stat(fileName); os.IsNotExist(err) { 39 | return "", fmt.Errorf("binary not found: %s, %v", fileName, err) 40 | } 41 | } else { 42 | return "", fmt.Errorf("binary not found: %s, %v", fileName, err) 43 | } 44 | } 45 | return fileName, nil 46 | } 47 | 48 | func IsRunning(s cmd.Status) bool { 49 | return s.Error == nil && s.StartTs > 0 && !s.Complete && s.Exit == -1 50 | } 51 | 52 | func LogContainsText(s cmd.Status, text string) bool { 53 | for _, line := range s.Stdout { 54 | if strings.Contains(line, text) { 55 | return true 56 | } 57 | } 58 | for _, line := range s.Stderr { 59 | if strings.Contains(line, text) { 60 | return true 61 | } 62 | } 63 | return false 64 | } 65 | 66 | func WhatsWrong(s cmd.Status) error { 67 | if s.Error != nil { 68 | return s.Error 69 | } 70 | 71 | marshal, err := json.Marshal(s) 72 | if err != nil { 73 | return err 74 | } 75 | return errors.New("debug info: " + string(marshal)) 76 | } 77 | 78 | // WaitForRunningOrFail checks if stdout or stderr has content when mustWaitForStdOutput is true. 79 | // mustWaitForStdOutput is useful when the OS performs security checks on the binary, which can be 80 | // terribly slow on macOS. 81 | func WaitForRunningOrFail(t *testing.T, c *cmd.Cmd, mustWaitForStdOutput bool) { 82 | timer := time.NewTimer(100 * time.Second) 83 | ticker := time.NewTicker(100 * time.Millisecond) 84 | defer timer.Stop() 85 | defer ticker.Stop() 86 | 87 | for { 88 | select { 89 | case <-timer.C: 90 | t.Fatalf("failed to start: %v", WhatsWrong(c.Status())) 91 | case <-ticker.C: 92 | status := c.Status() 93 | if IsRunning(status) { 94 | if mustWaitForStdOutput { 95 | if len(status.Stdout) > 0 || len(status.Stderr) > 0 { 96 | return 97 | } 98 | } else { 99 | return 100 | } 101 | } 102 | } 103 | } 104 | 105 | } 106 | 107 | func RootDir(t *testing.T) string { 108 | cmdOut, err := exec.Command("git", "rev-parse", "--show-toplevel").Output() 109 | assert.NoError(t, err) 110 | return strings.TrimSpace(string(cmdOut)) 111 | } 112 | -------------------------------------------------------------------------------- /tests/framework/util_test.go: -------------------------------------------------------------------------------- 1 | package framework 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestRootDir(t *testing.T) { 12 | wd, err := os.Getwd() 13 | assert.NoError(t, err) 14 | 15 | rootDir := filepath.Dir(filepath.Dir(wd)) 16 | assert.Equal(t, RootDir(t), rootDir) 17 | } 18 | -------------------------------------------------------------------------------- /ts/.env.development: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_BACKEND_URL=http://localhost:8300 -------------------------------------------------------------------------------- /ts/.eslintignore: -------------------------------------------------------------------------------- 1 | .now/* 2 | *.css 3 | .changeset 4 | esm/* 5 | public/* 6 | tests/* 7 | scripts/* 8 | *.config.js 9 | .DS_Store 10 | node_modules 11 | coverage 12 | .next 13 | !.commitlintrc.cjs 14 | !.lintstagedrc.cjs 15 | !jest.config.js 16 | !plopfile.js 17 | !react-shim.js 18 | !tsup.config.ts -------------------------------------------------------------------------------- /ts/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/eslintrc.json", 3 | "env": { 4 | "browser": false, 5 | "es2021": true, 6 | "node": true 7 | }, 8 | "extends": [ 9 | "plugin:react/recommended", 10 | "plugin:prettier/recommended", 11 | "plugin:react-hooks/recommended", 12 | "plugin:jsx-a11y/recommended" 13 | ], 14 | "plugins": [ 15 | "react", 16 | "unused-imports", 17 | "import", 18 | "@typescript-eslint", 19 | "jsx-a11y", 20 | "prettier" 21 | ], 22 | "parser": "@typescript-eslint/parser", 23 | "parserOptions": { 24 | "ecmaFeatures": { 25 | "jsx": true 26 | }, 27 | "ecmaVersion": 12, 28 | "sourceType": "module" 29 | }, 30 | "settings": { 31 | "react": { 32 | "version": "detect" 33 | } 34 | }, 35 | "rules": { 36 | "no-console": "off", 37 | "react/prop-types": "off", 38 | "react/jsx-uses-react": "off", 39 | "react/react-in-jsx-scope": "off", 40 | "react-hooks/exhaustive-deps": "off", 41 | "jsx-a11y/click-events-have-key-events": "warn", 42 | "jsx-a11y/interactive-supports-focus": "warn", 43 | "prettier/prettier": "warn", 44 | "no-unused-vars": "off", 45 | "unused-imports/no-unused-vars": "off", 46 | "unused-imports/no-unused-imports": "warn", 47 | "@typescript-eslint/no-unused-vars": [ 48 | "warn", 49 | { 50 | "args": "after-used", 51 | "ignoreRestSiblings": false, 52 | "argsIgnorePattern": "^_.*?$" 53 | } 54 | ], 55 | "import/order": [ 56 | "warn", 57 | { 58 | "groups": [ 59 | "type", 60 | "builtin", 61 | "object", 62 | "external", 63 | "internal", 64 | "parent", 65 | "sibling", 66 | "index" 67 | ], 68 | "pathGroups": [ 69 | { 70 | "pattern": "~/**", 71 | "group": "external", 72 | "position": "after" 73 | } 74 | ], 75 | "newlines-between": "always" 76 | } 77 | ], 78 | "react/self-closing-comp": "warn", 79 | "react/jsx-sort-props": [ 80 | "warn", 81 | { 82 | "callbacksLast": true, 83 | "shorthandFirst": true, 84 | "noSortAlphabetically": false, 85 | "reservedFirst": true 86 | } 87 | ] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ts/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | components/api/* -------------------------------------------------------------------------------- /ts/.npmrc: -------------------------------------------------------------------------------- 1 | public-hoist-pattern[]=*@nextui-org/* 2 | package-lock=false 3 | -------------------------------------------------------------------------------- /ts/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Next UI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ts/Makefile: -------------------------------------------------------------------------------- 1 | # mode=grpcwebtext prevents client from receiving all the messages at once when using streaming 2 | .PHONY: build 3 | 4 | all: protoc disable-telemetry test build 5 | 6 | protoc: 7 | @echo "Generating protobuf files for ts" 8 | @if [ ! -d "./components/api" ]; then \ 9 | mkdir ./components/api; \ 10 | fi 11 | pnpm install -g protoc-gen-js protoc-gen-grpc-web 12 | protoc -I=../proto api.proto \ 13 | --js_out=import_style=commonjs,binary:./components/api \ 14 | --grpc-web_out=import_style=typescript,mode=grpcwebtext:./components/api 15 | 16 | build: install 17 | @echo "Building ts" 18 | pnpm build 19 | 20 | test: install 21 | @echo "Testing ts" 22 | pnpm test 23 | 24 | install: 25 | @echo "Installing dependencies for ts" 26 | pnpm install 27 | 28 | disable-telemetry: 29 | @echo "Disabling Next.js telemetry" 30 | npx next telemetry --disable 31 | 32 | analyze: 33 | ANALYZE=true pnpm build 34 | 35 | clean: 36 | @echo "Cleaning ts" 37 | rm -rf out 38 | -------------------------------------------------------------------------------- /ts/README.md: -------------------------------------------------------------------------------- 1 | # Next.js & NextUI Template 2 | 3 | This is a template for creating applications using Next.js 14 (app directory) and NextUI (v2). 4 | 5 | [Try it on CodeSandbox](https://githubbox.com/nextui-org/next-app-template) 6 | 7 | ## Technologies Used 8 | 9 | - [Next.js 14](https://nextjs.org/docs/getting-started) 10 | - [NextUI v2](https://nextui.org/) 11 | - [Tailwind CSS](https://tailwindcss.com/) 12 | - [Tailwind Variants](https://tailwind-variants.org) 13 | - [TypeScript](https://www.typescriptlang.org/) 14 | - [Framer Motion](https://www.framer.com/motion/) 15 | - [next-themes](https://github.com/pacocoursey/next-themes) 16 | 17 | ## How to Use 18 | 19 | ### Use the template with create-next-app 20 | 21 | To create a new project based on this template using `create-next-app`, run the following command: 22 | 23 | ```bash 24 | npx create-next-app -e https://github.com/nextui-org/next-app-template 25 | ``` 26 | 27 | ### Install dependencies 28 | 29 | You can use one of them `npm`, `yarn`, `pnpm`, `bun`, Example using `npm`: 30 | 31 | ```bash 32 | npm install 33 | ``` 34 | 35 | ### Run the development server 36 | 37 | ```bash 38 | npm run dev 39 | ``` 40 | 41 | ### Setup pnpm (optional) 42 | 43 | If you are using `pnpm`, you need to add the following code to your `.npmrc` file: 44 | 45 | ```bash 46 | public-hoist-pattern[]=*@nextui-org/* 47 | ``` 48 | 49 | After modifying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly. 50 | 51 | ## License 52 | 53 | Licensed under the [MIT license](https://github.com/nextui-org/next-app-template/blob/main/LICENSE). 54 | -------------------------------------------------------------------------------- /ts/app/about/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function AboutLayout({ children }: { children: React.ReactNode }) { 2 | return ( 3 |
4 |
{children}
5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /ts/app/about/page.tsx: -------------------------------------------------------------------------------- 1 | import { title } from '@/components/primitives' 2 | 3 | export default function AboutPage() { 4 | return ( 5 |
6 |

About

7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /ts/app/blog/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function BlogLayout({ children }: { children: React.ReactNode }) { 2 | return ( 3 |
4 |
{children}
5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /ts/app/blog/page.tsx: -------------------------------------------------------------------------------- 1 | import { title } from '@/components/primitives' 2 | 3 | export default function BlogPage() { 4 | return ( 5 |
6 |

Blog

7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /ts/app/docs/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function DocsLayout({ children }: { children: React.ReactNode }) { 2 | return ( 3 |
4 |
{children}
5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /ts/app/docs/page.tsx: -------------------------------------------------------------------------------- 1 | import { title } from '@/components/primitives' 2 | 3 | export default function DocsPage() { 4 | return ( 5 |
6 |

Docs

7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /ts/app/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect } from 'react' 4 | 5 | export default function Error({ error, reset }: { error: Error; reset: () => void }) { 6 | useEffect(() => { 7 | // Log the error to an error reporting service 8 | /* eslint-disable no-console */ 9 | console.error(error) 10 | }, [error]) 11 | 12 | return ( 13 |
14 |

Something went wrong!

15 | 23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /ts/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@/styles/globals.css' 2 | import { Metadata, Viewport } from 'next' 3 | import clsx from 'clsx' 4 | 5 | import { Providers } from './providers' 6 | 7 | import { siteConfig } from '@/config/site' 8 | import { fontSans } from '@/config/fonts' 9 | import { Navbar } from '@/components/navbar' 10 | 11 | export const metadata: Metadata = { 12 | title: { 13 | default: siteConfig.name, 14 | template: `%s - ${siteConfig.name}`, 15 | }, 16 | description: siteConfig.description, 17 | icons: { 18 | icon: '/favicon.ico', 19 | }, 20 | } 21 | 22 | export const viewport: Viewport = { 23 | themeColor: [ 24 | { media: '(prefers-color-scheme: light)', color: 'white' }, 25 | { media: '(prefers-color-scheme: dark)', color: 'black' }, 26 | ], 27 | } 28 | 29 | export default function RootLayout({ children }: { children: React.ReactNode }) { 30 | return ( 31 | 32 | 33 | Live pprof 34 | 35 | 36 | 37 |
38 | 39 |
{children}
40 |
41 |
42 | 43 | 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /ts/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react' 2 | 3 | import { AllGraphs } from '@/components/all-graphs' 4 | 5 | export default function Home() { 6 | return ( 7 | 8 | 9 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /ts/app/pricing/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function PricingLayout({ children }: { children: React.ReactNode }) { 2 | return ( 3 |
4 |
{children}
5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /ts/app/pricing/page.tsx: -------------------------------------------------------------------------------- 1 | import { title } from '@/components/primitives' 2 | 3 | export default function PricingPage() { 4 | return ( 5 |
6 |

Pricing

7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /ts/app/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { NextUIProvider } from '@nextui-org/system' 5 | import { useRouter } from 'next/navigation' 6 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 7 | import { ThemeProviderProps } from 'next-themes/dist/types' 8 | 9 | export interface ProvidersProps { 10 | children: React.ReactNode 11 | themeProps?: ThemeProviderProps 12 | } 13 | 14 | export function Providers({ children, themeProps }: ProvidersProps) { 15 | const router = useRouter() 16 | 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /ts/components/about-modal.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { FC, useEffect } from 'react' 4 | import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, useDisclosure } from '@nextui-org/modal' 5 | import { Button } from '@nextui-org/button' 6 | import { Link } from '@nextui-org/link' 7 | import { AnchorIcon } from '@nextui-org/shared-icons' 8 | 9 | import { uiState } from '@/components/state/ui-state' 10 | 11 | export const AboutModal: FC = () => { 12 | const { isOpen, onOpen, onOpenChange } = useDisclosure() 13 | 14 | useEffect(() => { 15 | uiState.openAboutModal = onOpen 16 | return () => { 17 | uiState.openAboutModal = () => {} 18 | } 19 | }, []) 20 | 21 | return ( 22 | 23 | 24 | {onClose => ( 25 | <> 26 | About 27 | 28 |
  • 29 | } 33 | color={'foreground'} 34 | href="https://stackoverflow.com/a/56882137" 35 | > 36 | The charts display flat pprof data, not cumulative 37 | 38 |
  • 39 |
    40 | 41 | 44 | 45 | 46 | )} 47 |
    48 |
    49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /ts/components/all-graphs.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import React, { useEffect } from 'react' 3 | import { registerTheme } from 'echarts' 4 | import { useIsSSR } from '@react-aria/ssr' 5 | 6 | import { ChartOption } from '@/components/chart-option' 7 | import darkTheme from '@/components/charts/dark-theme' 8 | import { PprofType } from '@/components/hooks/use-graph-data' 9 | import { PprofGraph } from '@/components/charts/pprof-chart' 10 | import { useWindowListener } from '@/components/window-listener' 11 | import { useGraphPrefSnap } from '@/components/hooks/use-graph-pref-snap' 12 | import { useParamAction } from '@/components/hooks/use-param-action' 13 | 14 | registerTheme('dark', darkTheme()) 15 | 16 | export const AllGraphs: React.FC = () => { 17 | const ssr = useIsSSR() 18 | useWindowListener() 19 | useParamAction() 20 | const [cpu, heap, allocs, goroutine] = [ 21 | useGraphPrefSnap(PprofType.cpu), 22 | useGraphPrefSnap(PprofType.heap), 23 | useGraphPrefSnap(PprofType.allocs), 24 | useGraphPrefSnap(PprofType.goroutine), 25 | ] 26 | 27 | useEffect(() => { 28 | if (ssr) return 29 | }, [ssr]) 30 | 31 | return ( 32 |
    33 | {[cpu, heap, allocs, goroutine] 34 | .filter(snap => snap.prefSnap.enabled) 35 | .map(snap => ( 36 |
    37 | 41 | 42 |
    43 | ))} 44 |
    45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /ts/components/charts/basic-graph.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import React, { useEffect, useRef } from 'react' 3 | import { useTheme } from 'next-themes' 4 | import ReactECharts from 'echarts-for-react' 5 | import { EChartsType } from 'echarts' 6 | import { EChartsOption } from 'echarts-for-react/src/types' 7 | import clsx from 'clsx' 8 | 9 | type BasicGraphProps = { 10 | option: EChartsOption 11 | refreshKey?: string 12 | className?: string 13 | } 14 | 15 | export const BasicGraph: React.FC = ({ option, refreshKey, className }) => { 16 | const theme = useTheme() 17 | const ref = useRef() 18 | 19 | useEffect(() => { 20 | const chart = ref.current?.getEchartsInstance() as EChartsType 21 | if (chart) { 22 | chart.getZr().on('click', (params: any) => {}) 23 | chart.getZr().on('dblclick', (params: any) => {}) 24 | } 25 | }, [ref]) 26 | 27 | return ( 28 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /ts/components/charts/data-operation.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { GraphData, Point } from '@/components/charts/data-structure' 3 | import { GoMetricsResponse, Item } from '@/components/api/api_pb' 4 | import { convertUnixNanoToDate } from '@/components/util/util' 5 | 6 | const getKey = (item: Item): string => item.getFunc() + ' ' + item.getLine() 7 | 8 | export function appendGraphData( 9 | graphData: GraphData, 10 | rsp: GoMetricsResponse, 11 | topN: number, 12 | retainedSamples?: number 13 | ): GraphData { 14 | let date = convertUnixNanoToDate(rsp.getDate()) 15 | 16 | let items = rsp 17 | .getItemsList() 18 | .filter(item => item.getFlat() > 0) 19 | .sort((a, b) => b.getFlat() - a.getFlat()) 20 | .slice(0, topN) 21 | 22 | graphData.dates.push(date) 23 | 24 | const count = graphData.dates.length 25 | 26 | if (retainedSamples && count > 0 && count > retainedSamples) { 27 | const datesToDelete = graphData.dates.splice(0, count - retainedSamples) 28 | datesToDelete.forEach(d => 29 | Object.keys(graphData.lineTable).forEach(key => { 30 | const line = graphData.lineTable[key] 31 | line.points = line.points.filter(p => p.date !== d) 32 | }) 33 | ) 34 | } 35 | 36 | for (let key in graphData.lineTable) { 37 | graphData.lineTable[key].points.push({ 38 | date: date, 39 | flat: undefined, 40 | cum: undefined, 41 | }) 42 | } 43 | 44 | for (let item of items) { 45 | const key = getKey(item) 46 | let line = graphData.lineTable[key] 47 | if (!line) { 48 | const nullPoints = graphData.dates.map( 49 | (d): Point => ({ 50 | date: d, 51 | flat: undefined, 52 | cum: undefined, 53 | }) 54 | ) 55 | line = { 56 | name: key, 57 | points: nullPoints, 58 | } 59 | graphData.lineTable[key] = line 60 | } 61 | const last = line.points[line.points.length - 1] 62 | line.points[line.points.length - 1] = { ...last, flat: item.getFlat(), cum: item.getCum() } 63 | } 64 | return { ...graphData } 65 | } 66 | -------------------------------------------------------------------------------- /ts/components/charts/data-structure.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | export type Point = { 3 | date: Date 4 | flat: number | undefined 5 | cum: number | undefined 6 | } 7 | 8 | export type Line = { 9 | name: string 10 | points: Point[] 11 | } 12 | 13 | export type LineTable = Record 14 | 15 | export type GraphData = { 16 | lineTable: LineTable 17 | dates: Date[] 18 | } 19 | 20 | export const newGraphData = (): GraphData => ({ lineTable: {}, dates: [] }) 21 | -------------------------------------------------------------------------------- /ts/components/charts/pprof-chart.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import React, { FC } from 'react' 3 | 4 | import { PprofType } from '@/components/hooks/use-graph-data' 5 | import { BasicGraph } from '@/components/charts/basic-graph' 6 | import { usePprofOption } from '@/components/hooks/use-pprof-option' 7 | 8 | type PprofGraphProps = { 9 | pprofType: PprofType 10 | className?: string 11 | } 12 | 13 | export const PprofGraph: FC = ({ pprofType, className }) => { 14 | let [option, refreshKey] = usePprofOption({ pprofType: pprofType }) 15 | 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /ts/components/client/metrics.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useSnapshot } from 'valtio/react' 4 | import { useMemo } from 'react' 5 | import { useIsSSR } from '@react-aria/ssr' 6 | 7 | import { GeneralClient, MetricsClient, MockMetricsClient } from '@/components/api/ApiServiceClientPb' 8 | import { graphPrefsState } from '@/components/state/pref-state' 9 | import { useIsDev } from '@/components/hooks/use-is-dev' 10 | 11 | const blackHole = 'http://240.0.0.0:8300' 12 | 13 | export const useBackendURL = (): string => { 14 | const isDev = useIsDev() 15 | const isSSR = useIsSSR() 16 | if (isSSR) { 17 | // black hole 18 | return blackHole 19 | } 20 | 21 | if (isDev) { 22 | return process.env.NEXT_PUBLIC_BACKEND_URL! 23 | } else { 24 | return `${window.location.protocol}//${window.location.hostname}:${window.location.port}` 25 | } 26 | } 27 | 28 | export const useMetricsClient = (): MetricsClient => { 29 | const { mock } = useSnapshot(graphPrefsState) 30 | const url = useBackendURL() 31 | return useMemo(() => (mock ? new MockMetricsClient(url) : new MetricsClient(url)), [mock, url]) 32 | } 33 | 34 | export const useGeneralClient = (): GeneralClient => { 35 | const url = useBackendURL() 36 | return useMemo(() => new GeneralClient(url), [url]) 37 | } 38 | -------------------------------------------------------------------------------- /ts/components/hooks/__test__/set-url.test.tsx: -------------------------------------------------------------------------------- 1 | import { expect, test } from 'vitest' 2 | import { renderHook } from '@testing-library/react' 3 | 4 | import { useURL } from '@/components/hooks/use-url' 5 | import { graphPrefsState } from '@/components/state/pref-state' 6 | 7 | test('useURL-port', () => { 8 | const render = renderHook(() => useURL()) 9 | 10 | for (const port of [1, 8899, 65535]) { 11 | graphPrefsState.inputURL = `${port}` 12 | render.rerender() 13 | const { url } = render.result.current 14 | expect(url).toBeTypeOf('string') 15 | expect(url).toBe(`http://localhost:${port}/debug/pprof`) 16 | } 17 | 18 | for (const port of [-1, 0, -0, 65536, 999999]) { 19 | graphPrefsState.inputURL = `${port}` 20 | render.rerender() 21 | const { url } = render.result.current 22 | expect(url instanceof Error).toBeTruthy() 23 | expect((url as Error).message).includes('out of range') 24 | } 25 | 26 | for (const element of [-11.1, 9090.1]) { 27 | graphPrefsState.inputURL = `${element}` 28 | render.rerender() 29 | const { url } = render.result.current 30 | expect(url instanceof Error).toBeTruthy() 31 | expect((url as Error).message).includes('Invalid URL') 32 | } 33 | }) 34 | 35 | test('useURL localhost', () => { 36 | const render = renderHook(() => useURL()) 37 | 38 | for (const element of ['localhost', 'http://localhost', 'http://localhost/']) { 39 | graphPrefsState.inputURL = element 40 | render.rerender() 41 | const { url } = render.result.current 42 | expect(url).toBeTypeOf('string') 43 | expect(url).toBe('http://localhost') 44 | } 45 | 46 | graphPrefsState.inputURL = 'localhost:80' 47 | render.rerender() 48 | let { url } = render.result.current 49 | expect(url).toBeTypeOf('string') 50 | expect(url).toBe('http://localhost:80') 51 | 52 | graphPrefsState.inputURL = 'localhost:21' 53 | render.rerender() 54 | url = render.result.current.url 55 | expect(url).toBeTypeOf('string') 56 | expect(url).toBe('http://localhost:21') 57 | 58 | for (const element of [ 59 | 'localhost/ab/c-d', 60 | 'localhost//ab//c-d', 61 | 'http://localhost/ab/c-d', 62 | 'http://localhost/ab/c-d', 63 | ]) { 64 | graphPrefsState.inputURL = element 65 | render.rerender() 66 | const { url } = render.result.current 67 | expect(url).toBeTypeOf('string') 68 | expect(url).toBe('http://localhost/ab/c-d') 69 | } 70 | 71 | for (const element of ['https://localhost/ab/c-d']) { 72 | graphPrefsState.inputURL = element 73 | render.rerender() 74 | const { url } = render.result.current 75 | expect(url).toBeTypeOf('string') 76 | expect(url).toBe('https://localhost/ab/c-d') 77 | } 78 | }) 79 | -------------------------------------------------------------------------------- /ts/components/hooks/use-basic-option.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { useTheme } from "next-themes" 3 | import { EChartsOption } from "echarts-for-react/src/types" 4 | import { FC } from "react" 5 | import { snapshot } from "valtio" 6 | 7 | import { CursorQuadrant, getCursorQuadrant, uiState } from "@/components/state/ui-state" 8 | 9 | export type BasicProps = { 10 | labelFormatter?: (value: number) => string 11 | } 12 | 13 | export const useBasicOption: FC = ({ labelFormatter }): EChartsOption => { 14 | const theme = useTheme() 15 | return basicOption(theme.resolvedTheme === "dark", labelFormatter) 16 | } 17 | 18 | export const basicOption = ( 19 | isDark: boolean, 20 | labelFormatter: ((value: number) => string) | undefined 21 | ): EChartsOption => { 22 | return { 23 | animationDuration: 0, 24 | dataZoom: [ 25 | { 26 | type: "slider", 27 | show: true, 28 | xAxisIndex: [0] 29 | }, 30 | { 31 | type: "slider", 32 | show: true, 33 | showDataShadow: false, 34 | yAxisIndex: [0], 35 | labelFormatter: labelFormatter 36 | }, 37 | { 38 | type: "inside", 39 | xAxisIndex: [0] 40 | } 41 | ], 42 | toolbox: { 43 | feature: { 44 | saveAsImage: {}, 45 | restore: {} 46 | } 47 | }, 48 | grid: { 49 | right: 50, 50 | left: 50 51 | }, 52 | xAxis: { 53 | axisLabel: { 54 | margin: 20, 55 | hideOverlap: true 56 | } 57 | }, 58 | tooltip: { 59 | order: "valueDesc", 60 | trigger: "axis", 61 | triggerOn: "mousemove", 62 | backgroundColor: isDark ? "#2e2e2e" : "white", 63 | borderColor: isDark ? "#2e2e2e" : "white", 64 | textStyle: isDark 65 | ? { 66 | color: "#e3e3e3" 67 | } 68 | : null, 69 | position: function (point: Array, _params: any | Array, dom: HTMLElement, _rect: any, _size: any) { 70 | const uiSnap = snapshot(uiState) 71 | const cq = getCursorQuadrant(uiSnap.cursorPos.x, uiSnap.cursorPos.y) 72 | 73 | switch (cq) { 74 | case CursorQuadrant.First: 75 | // place tooltip at left bottom of the pointer 76 | return [point[0] - dom.clientWidth - 20, point[1] + 30] 77 | case CursorQuadrant.Second: 78 | // place tooltip at right bottom of the pointer 79 | return [point[0] + 20, point[1] + 30] 80 | case CursorQuadrant.Third: 81 | // place tooltip at right top of the pointer 82 | return [point[0] + 20, point[1] - 30 - dom.clientHeight] 83 | case CursorQuadrant.Fourth: 84 | // place tooltip at left top of the pointer 85 | return [point[0] - dom.clientWidth - 20, point[1] - 30 - dom.clientHeight] 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ts/components/hooks/use-graph-pref-snap.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { useCallback } from 'react' 3 | import { useSnapshot } from 'valtio/react' 4 | 5 | import { PprofType } from '@/components/hooks/use-graph-data' 6 | import { 7 | dispatchGraphPrefDescription, 8 | dispatchGraphPrefIconName, 9 | dispatchGraphPrefLeftOffsetLarge, 10 | dispatchGraphPrefProxy, 11 | GraphPref, 12 | } from '@/components/state/pref-state' 13 | 14 | export const useGraphPrefSnap: (pprofType: PprofType) => { 15 | prefSnap: GraphPref 16 | toggleEnabled: () => void 17 | iconName: string 18 | description: string 19 | pprofType: PprofType 20 | leftOffsetLarge: boolean 21 | } = (pprofType: PprofType) => { 22 | const proxy = dispatchGraphPrefProxy(pprofType) 23 | const snap = useSnapshot(proxy) 24 | 25 | const toggleEnabled = useCallback(() => { 26 | proxy.enabled = !proxy.enabled 27 | }, []) 28 | 29 | const iconName = dispatchGraphPrefIconName(pprofType) 30 | const description = dispatchGraphPrefDescription(pprofType) 31 | const leftOffsetLarge = dispatchGraphPrefLeftOffsetLarge(pprofType) 32 | return { 33 | prefSnap: snap, 34 | toggleEnabled: toggleEnabled, 35 | iconName: iconName, 36 | description: description, 37 | pprofType: pprofType, 38 | leftOffsetLarge: leftOffsetLarge, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ts/components/hooks/use-is-dev.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useLayoutEffect, useState } from 'react' 4 | 5 | export const useIsDev = (): boolean => { 6 | const [isDev, setIsDev] = useState(false) 7 | 8 | useLayoutEffect(() => { 9 | setIsDev(process.env.NODE_ENV === 'development') 10 | }, []) 11 | 12 | return isDev 13 | } 14 | -------------------------------------------------------------------------------- /ts/components/hooks/use-param-action.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect } from 'react' 4 | import { useRouter, useSearchParams } from 'next/navigation' 5 | 6 | import { generateUrl, useURL } from '@/components/hooks/use-url' 7 | import { recorderState } from '@/components/state/recorder-state' 8 | 9 | // useParamAction parses url params and converts them into actions. 10 | // These parameters are added to the URL when the backend opens it in the browser. 11 | export const useParamAction = (): void => { 12 | const sp = useSearchParams() 13 | const router = useRouter() 14 | const { setInput } = useURL() 15 | 16 | const pprofURL = sp.get('pprof-url') 17 | 18 | useEffect(() => { 19 | router.push(window.location.pathname) 20 | let t: NodeJS.Timeout 21 | if (pprofURL) { 22 | console.info('param: pprof-url', pprofURL) 23 | setInput(pprofURL) 24 | if (typeof generateUrl(pprofURL) === 'string') { 25 | // it's a valid url 26 | t = setTimeout(() => { 27 | console.info('start recording') 28 | recorderState.isRecording = true 29 | }) 30 | } 31 | } 32 | return () => clearTimeout(t) 33 | }, [router, setInput]) 34 | } 35 | -------------------------------------------------------------------------------- /ts/components/hooks/use-profile-duration.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useSnapshot } from "valtio/react" 4 | import { floor } from "lodash" 5 | 6 | import { graphPrefsState } from "@/components/state/pref-state" 7 | 8 | export const useProfileDuration = (): { seconds: number } => { 9 | const { sampleInterval } = useSnapshot(graphPrefsState) 10 | 11 | const sec = sampleInterval > 1000 ? floor(sampleInterval / 1000) : 1 12 | 13 | return { seconds: sec } 14 | } 15 | -------------------------------------------------------------------------------- /ts/components/hooks/use-url.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useCallback, useMemo } from 'react' 4 | import { useSnapshot } from 'valtio/react' 5 | import getUrls from 'get-urls' 6 | 7 | import { graphPrefsState } from '@/components/state/pref-state' 8 | 9 | export const useURL = (): { url: string | Error; input: string; setInput: (input: string) => void } => { 10 | const { inputURL } = useSnapshot(graphPrefsState, { sync: true }) 11 | 12 | const setInput = useCallback((input: string) => { 13 | graphPrefsState.inputURL = input 14 | }, []) 15 | 16 | const url = useMemo(() => generateUrl(inputURL), [inputURL]) 17 | 18 | return { url: url, input: inputURL, setInput: setInput } 19 | } 20 | 21 | export const generateUrl = (input: string): string | Error => { 22 | const port = Number(input) 23 | if (input === '') { 24 | return new Error('Please input the URL of pprof endpoint') 25 | } else if (Number.isInteger(port)) { 26 | if (port >= 1 && port <= 65535) { 27 | return `http://localhost:${port}/debug/pprof` 28 | } else { 29 | return new Error(`Port ${port} is out of range: [1, 65535]`) 30 | } 31 | } else { 32 | const urls = getUrls(input) 33 | const next = urls.values().next() 34 | if (!next.done) { 35 | let v = next.value 36 | // workaround for getUrls as it may return an URL without the scheme prefix 37 | // noinspection HttpUrlsUsage 38 | if (!v.startsWith('http://') && !v.startsWith('https://')) { 39 | // noinspection HttpUrlsUsage 40 | v = `http://${v}` 41 | } 42 | return v 43 | } 44 | 45 | return new Error('Invalid URL') 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ts/components/mock-switch.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { FC } from 'react' 4 | import { Switch, SwitchProps } from '@nextui-org/switch' 5 | import { useSnapshot } from 'valtio/react' 6 | import clsx from 'clsx' 7 | import { Icon } from '@iconify/react' 8 | import { useIsSSR } from '@react-aria/ssr' 9 | import { Tooltip } from '@nextui-org/tooltip' 10 | 11 | import { graphPrefsState } from '@/components/state/pref-state' 12 | import { useIsDev } from '@/components/hooks/use-is-dev' 13 | 14 | export interface ThemeSwitchProps { 15 | className?: string 16 | classNames?: SwitchProps['classNames'] 17 | } 18 | 19 | export const MockSwitch: FC = ({ className, classNames }) => { 20 | const { mock } = useSnapshot(graphPrefsState) 21 | const isDev = useIsDev() 22 | if (useIsSSR() || !isDev) { 23 | return null 24 | } 25 | 26 | return ( 27 | 28 | } 34 | onValueChange={v => { 35 | graphPrefsState.mock = v 36 | }} 37 | /> 38 | 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /ts/components/navbar.tsx: -------------------------------------------------------------------------------- 1 | import { Navbar as NextUINavbar, NavbarBrand, NavbarContent, NavbarItem } from '@nextui-org/navbar' 2 | import { Link } from '@nextui-org/link' 3 | import NextLink from 'next/link' 4 | 5 | import { siteConfig } from '@/config/site' 6 | import { ThemeSwitch } from '@/components/theme-switch' 7 | import { GithubIcon } from '@/components/icons' 8 | import { MockSwitch } from '@/components/mock-switch' 9 | import { RecorderButton } from '@/components/recorder-button' 10 | import { RecorderTime } from '@/components/recorder-time' 11 | import UrlBar from '@/components/url-bar' 12 | import { HomeMenu } from '@/components/home-menu' 13 | import { AboutModal } from '@/components/about-modal' 14 | 15 | export const Navbar = () => { 16 | return ( 17 | 18 | 19 | 20 | 21 |

    Live pprof

    22 |
    23 |
    24 |
      25 | 26 | 27 | 28 | 29 |
    30 |
    31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
    43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /ts/components/primitives.ts: -------------------------------------------------------------------------------- 1 | import { tv } from 'tailwind-variants' 2 | 3 | export const title = tv({ 4 | base: 'tracking-tight inline font-semibold', 5 | variants: { 6 | color: { 7 | violet: 'from-[#FF1CF7] to-[#b249f8]', 8 | yellow: 'from-[#FF705B] to-[#FFB457]', 9 | blue: 'from-[#5EA2EF] to-[#0072F5]', 10 | cyan: 'from-[#00b7fa] to-[#01cfea]', 11 | green: 'from-[#6FEE8D] to-[#17c964]', 12 | pink: 'from-[#FF72E1] to-[#F54C7A]', 13 | foreground: 'dark:from-[#FFFFFF] dark:to-[#4B4B4B]', 14 | }, 15 | size: { 16 | sm: 'text-3xl lg:text-4xl', 17 | md: 'text-[2.3rem] lg:text-5xl leading-9', 18 | lg: 'text-4xl lg:text-6xl', 19 | }, 20 | fullWidth: { 21 | true: 'w-full block', 22 | }, 23 | }, 24 | defaultVariants: { 25 | size: 'md', 26 | }, 27 | compoundVariants: [ 28 | { 29 | color: ['violet', 'yellow', 'blue', 'cyan', 'green', 'pink', 'foreground'], 30 | class: 'bg-clip-text text-transparent bg-gradient-to-b', 31 | }, 32 | ], 33 | }) 34 | 35 | export const subtitle = tv({ 36 | base: 'w-full md:w-1/2 my-2 text-lg lg:text-xl text-default-600 block max-w-full', 37 | variants: { 38 | fullWidth: { 39 | true: '!w-full', 40 | }, 41 | }, 42 | defaultVariants: { 43 | fullWidth: true, 44 | }, 45 | }) 46 | -------------------------------------------------------------------------------- /ts/components/recorder-button.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import React, { useCallback } from "react" 4 | import { useSnapshot } from "valtio/react" 5 | import { Tooltip } from "@nextui-org/tooltip" 6 | import { Button } from "@nextui-org/button" 7 | import { Icon } from "@iconify/react" 8 | 9 | import { recorderState } from "@/components/state/recorder-state" 10 | import { useURL } from "@/components/hooks/use-url" 11 | 12 | export const RecorderButton = () => { 13 | const { isRecording } = useSnapshot(recorderState) 14 | const { url } = useURL() 15 | const tooltipInfo = isRecording ? "Stop" : "Start" 16 | 17 | const start = useCallback(() => { 18 | recorderState.isRecording = true 19 | }, []) 20 | 21 | const stop = useCallback(() => { 22 | recorderState.isRecording = false 23 | }, []) 24 | 25 | return ( 26 | 27 | {isRecording ? ( 28 | 37 | ) : ( 38 | 48 | )} 49 | 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /ts/components/recorder-time.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React, { FC, useEffect } from 'react' 4 | import { useSnapshot } from 'valtio/react' 5 | import dayjs from 'dayjs' 6 | 7 | import { recorderState } from '@/components/state/recorder-state' 8 | import { formatMillis } from '@/components/util/util' 9 | 10 | export const RecorderTime: FC = () => { 11 | const { isRecording, currentMillis, totalMillis } = useSnapshot(recorderState) 12 | 13 | useEffect(() => { 14 | let t: NodeJS.Timeout 15 | if (isRecording) { 16 | recorderState.lastStarted = dayjs() 17 | t = setInterval(() => { 18 | recorderState.currentMillis = dayjs().diff(recorderState.lastStarted, 'milliseconds') 19 | }, 1000) 20 | } else { 21 | recorderState.totalMillis += recorderState.currentMillis 22 | recorderState.currentMillis = 0 23 | } 24 | return () => t && clearInterval(t) 25 | }, [isRecording]) 26 | 27 | const millis = currentMillis + totalMillis 28 | 29 | if (millis == 0 && !isRecording) return null 30 | 31 | return
    {formatMillis(millis)}
    32 | } 33 | -------------------------------------------------------------------------------- /ts/components/retained-samples.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Input } from '@nextui-org/input' 4 | import React, { useEffect, useState } from 'react' 5 | import { useIsSSR } from '@react-aria/ssr' 6 | import { useSnapshot } from 'valtio/react' 7 | 8 | import { graphPrefsState } from '@/components/state/pref-state' 9 | 10 | export const RetainedSamples = () => { 11 | const { retainedSamples } = useSnapshot(graphPrefsState) 12 | 13 | let [input, setInput] = useState(`${retainedSamples}`) 14 | 15 | useEffect(() => { 16 | if (!isInvalid()) { 17 | graphPrefsState.retainedSamples = Number(input) 18 | } 19 | }, [input]) 20 | 21 | const isInvalid = () => Number.isNaN(Number(input)) || Number(input) < 1 22 | 23 | if (useIsSSR()) { 24 | return null 25 | } 26 | 27 | return ( 28 | 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /ts/components/sample-interval.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Input } from '@nextui-org/input' 4 | import React, { useEffect, useState } from 'react' 5 | import { useIsSSR } from '@react-aria/ssr' 6 | import { useSnapshot } from 'valtio/react' 7 | 8 | import { graphPrefsState } from '@/components/state/pref-state' 9 | 10 | export const SampleInterval = () => { 11 | const { sampleInterval } = useSnapshot(graphPrefsState) 12 | 13 | let [input, setInput] = useState(`${sampleInterval}`) 14 | 15 | useEffect(() => { 16 | if (!isInvalid()) { 17 | graphPrefsState.sampleInterval = Number(input) 18 | } 19 | }, [input]) 20 | 21 | const isInvalid = () => Number.isNaN(Number(input)) || Number(input) < 100 22 | 23 | if (useIsSSR()) { 24 | return null 25 | } 26 | 27 | return ( 28 | 34 | ms 35 | 36 | } 37 | isInvalid={isInvalid()} 38 | label="Sample Interval" 39 | size={'sm'} 40 | type={'number'} 41 | value={`${input}`} 42 | variant="flat" 43 | onValueChange={setInput} 44 | /> 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /ts/components/smooth-switch.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { FC } from 'react' 4 | import { Switch, SwitchProps } from '@nextui-org/switch' 5 | import { useSnapshot } from 'valtio/react' 6 | import clsx from 'clsx' 7 | import { Icon } from '@iconify/react' 8 | import { useIsSSR } from '@react-aria/ssr' 9 | 10 | import { graphPrefsState } from '@/components/state/pref-state' 11 | import { CurveIcon } from '@/components/icons' 12 | 13 | export interface ThemeSwitchProps { 14 | className?: string 15 | classNames?: SwitchProps['classNames'] 16 | } 17 | 18 | export const SmoothSwitch: FC = ({ className, classNames }) => { 19 | const { smooth } = useSnapshot(graphPrefsState) 20 | const ssr = useIsSSR() 21 | if (ssr) { 22 | return null 23 | } 24 | 25 | return ( 26 |
    27 |

    Smooth Chart Lines

    28 | } 32 | isSelected={smooth} 33 | size={'sm'} 34 | startContent={} 35 | onValueChange={v => { 36 | graphPrefsState.smooth = v 37 | }} 38 | /> 39 |
    40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /ts/components/state/emitter.ts: -------------------------------------------------------------------------------- 1 | import mitt from 'mitt' 2 | 3 | export const myEmitter = mitt<{ clearData: undefined }>() 4 | -------------------------------------------------------------------------------- /ts/components/state/pref-state.ts: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { proxy, subscribe } from "valtio" 3 | 4 | import { PprofType } from "@/components/hooks/use-graph-data" 5 | 6 | const graphsPrefsLSKey = "graph-prefs-v24" 7 | 8 | export enum FlatOrCum { 9 | flat = "flat", 10 | cum = "cum" 11 | } 12 | 13 | export type GraphPref = { 14 | total: boolean 15 | flatOrCum: FlatOrCum 16 | enabled: boolean 17 | topN: number 18 | } 19 | 20 | const newGraphPref = (): GraphPref => ({ 21 | total: false, 22 | flatOrCum: FlatOrCum.flat, 23 | enabled: true, 24 | topN: 10 25 | }) 26 | 27 | export type GraphPrefs = { 28 | heap: GraphPref 29 | cpu: GraphPref 30 | allocs: GraphPref 31 | goroutine: GraphPref 32 | 33 | smooth: boolean 34 | mock: boolean 35 | inputURL: string 36 | retainedSamples: number 37 | sampleInterval: number // in ms 38 | } 39 | 40 | const newGraphPrefs = (): GraphPrefs => ({ 41 | heap: newGraphPref(), 42 | cpu: newGraphPref(), 43 | allocs: newGraphPref(), 44 | goroutine: newGraphPref(), 45 | 46 | smooth: false, 47 | mock: false, 48 | inputURL: `${8300}`, // get metrics from backend by default 49 | retainedSamples: 120, 50 | sampleInterval: 1000 51 | }) 52 | 53 | const IS_CLIENT = typeof window !== "undefined" 54 | 55 | export const graphPrefsState = proxy( 56 | IS_CLIENT ? JSON.parse(localStorage.getItem(graphsPrefsLSKey) as string) || newGraphPrefs() : newGraphPrefs() 57 | ) 58 | 59 | subscribe(graphPrefsState, () => { 60 | IS_CLIENT && localStorage.setItem(graphsPrefsLSKey, JSON.stringify(graphPrefsState)) 61 | }) 62 | 63 | export const dispatchGraphPrefProxy = (pt: PprofType): GraphPref => { 64 | switch (pt) { 65 | case PprofType.cpu: 66 | return graphPrefsState.cpu 67 | case PprofType.heap: 68 | return graphPrefsState.heap 69 | case PprofType.allocs: 70 | return graphPrefsState.allocs 71 | case PprofType.goroutine: 72 | return graphPrefsState.goroutine 73 | } 74 | } 75 | 76 | export const dispatchGraphPrefIconName = (pt: PprofType): string => { 77 | switch (pt) { 78 | case PprofType.cpu: 79 | // noinspection SpellCheckingInspection 80 | return "majesticons:cpu-line" 81 | case PprofType.heap: 82 | return "fa-solid:memory" 83 | case PprofType.allocs: 84 | return "fluent-emoji-high-contrast:new-button" 85 | case PprofType.goroutine: 86 | // noinspection SpellCheckingInspection 87 | return "nonicons:go-16" 88 | } 89 | } 90 | 91 | export const dispatchGraphPrefDescription = (pt: PprofType): string => { 92 | switch (pt) { 93 | case PprofType.cpu: 94 | return "cpu samples: /debug/pprof/profile?seconds=N" 95 | case PprofType.heap: 96 | return "inuse_space: /debug/pprof/heap" 97 | case PprofType.allocs: 98 | return "alloc_space: /debug/pprof/allocs" 99 | case PprofType.goroutine: 100 | return "goroutine: /debug/pprof/goroutine" 101 | } 102 | } 103 | 104 | export const dispatchGraphPrefLeftOffsetLarge = (pt: PprofType): boolean => { 105 | switch (pt) { 106 | case PprofType.cpu: 107 | case PprofType.heap: 108 | case PprofType.allocs: 109 | return false 110 | case PprofType.goroutine: 111 | return true 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ts/components/state/recorder-state.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { proxy } from 'valtio' 3 | import dayjs, { Dayjs } from 'dayjs' 4 | 5 | export type RecordingError = { 6 | date: Date 7 | msg: string 8 | } 9 | 10 | export type Recorder = { 11 | totalMillis: number 12 | 13 | isRecording: boolean 14 | lastStarted: Dayjs 15 | currentMillis: number 16 | 17 | errors: RecordingError[] 18 | } 19 | 20 | const newRecorder = (): Recorder => ({ 21 | totalMillis: 0, 22 | 23 | isRecording: false, 24 | lastStarted: dayjs(), 25 | currentMillis: 0, 26 | errors: [], 27 | }) 28 | 29 | export const recorderState = proxy(newRecorder()) 30 | 31 | export const resetRecorder = () => { 32 | recorderState.totalMillis = 0 33 | recorderState.currentMillis = 0 34 | recorderState.lastStarted = dayjs() 35 | } 36 | -------------------------------------------------------------------------------- /ts/components/state/ui-state.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { proxy } from 'valtio' 3 | 4 | type UI = { 5 | hoveringDate?: Date 6 | cursorPos: { x: number; y: number } 7 | openAboutModal: () => void 8 | } 9 | 10 | const newUI = (): UI => ({ 11 | cursorPos: { x: 0, y: 0 }, 12 | openAboutModal: () => {}, 13 | }) 14 | 15 | export const uiState = proxy(newUI()) 16 | 17 | export enum CursorQuadrant { 18 | First, 19 | Second, 20 | Third, 21 | Fourth, 22 | } 23 | 24 | export const getCursorQuadrant = (x: number, y: number): CursorQuadrant => { 25 | const cx = window.innerWidth / 2 26 | const cy = window.innerHeight / 2 27 | 28 | if (x >= cx && y <= cy) { 29 | return CursorQuadrant.First 30 | } else if (x < cx && y <= cy) { 31 | return CursorQuadrant.Second 32 | } else if (x < cx && y > cy) { 33 | return CursorQuadrant.Third 34 | } else { 35 | return CursorQuadrant.Fourth 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ts/components/theme-switch.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { FC } from 'react' 4 | import { VisuallyHidden } from '@react-aria/visually-hidden' 5 | import { SwitchProps, useSwitch } from '@nextui-org/switch' 6 | import { useTheme } from 'next-themes' 7 | import { useIsSSR } from '@react-aria/ssr' 8 | import clsx from 'clsx' 9 | 10 | import { SunFilledIcon, MoonFilledIcon } from '@/components/icons' 11 | 12 | export interface ThemeSwitchProps { 13 | className?: string 14 | classNames?: SwitchProps['classNames'] 15 | } 16 | 17 | export const ThemeSwitch: FC = ({ className, classNames }) => { 18 | const { theme, setTheme } = useTheme() 19 | const isSSR = useIsSSR() 20 | 21 | const onChange = () => { 22 | theme === 'light' ? setTheme('dark') : setTheme('light') 23 | } 24 | 25 | const { Component, slots, isSelected, getBaseProps, getInputProps, getWrapperProps } = useSwitch({ 26 | isSelected: theme === 'light' || isSSR, 27 | 'aria-label': `Switch to ${theme === 'light' || isSSR ? 'dark' : 'light'} mode`, 28 | onChange, 29 | }) 30 | 31 | return ( 32 | 37 | 38 | 39 | 40 |
    59 | {!isSelected || isSSR ? : } 60 |
    61 |
    62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /ts/components/url-bar.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import React from 'react' 3 | import { Popover, PopoverContent, PopoverTrigger } from '@nextui-org/popover' 4 | import { Chip } from '@nextui-org/chip' 5 | import { useIsSSR } from '@react-aria/ssr' 6 | 7 | import { UrlPopover } from '@/components/url-popover' 8 | import { useURL } from '@/components/hooks/use-url' 9 | 10 | export default function UrlBar() { 11 | const { url } = useURL() 12 | if (useIsSSR()) return null 13 | 14 | return ( 15 |
    16 | 17 | 18 | {url instanceof Error ? ( 19 | 20 | {url.message} 21 | 22 | ) : ( 23 | {url} 24 | )} 25 | 26 | 27 | 28 | 29 | 30 |
    31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /ts/components/url-popover.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-autofocus */ 2 | 'use client' 3 | 4 | import { Input } from '@nextui-org/input' 5 | import React, { useMemo } from 'react' 6 | import { useIsSSR } from '@react-aria/ssr' 7 | import { Chip } from '@nextui-org/chip' 8 | 9 | import { useURL } from '@/components/hooks/use-url' 10 | import { UrlDetect } from '@/components/url-detect' 11 | import { Link } from '@nextui-org/link' 12 | import { Icon } from '@iconify/react' 13 | import { Tooltip } from '@nextui-org/tooltip' 14 | 15 | export const UrlPopover = () => { 16 | const { url, input, setInput } = useURL() 17 | 18 | const isInvalid = useMemo(() => { 19 | return url instanceof Error 20 | }, [url]) 21 | 22 | if (useIsSSR()) { 23 | return null 24 | } 25 | 26 | const placeholder = '8300, localhost:8300 or http://localhost:8300/debug/pprof' 27 | return ( 28 |
    29 | {/* to provide auto inferred width for */} 30 |
    {placeholder}6chars6chars
    31 | 45 | {typeof url === 'string' && ( 46 |
    47 | 48 | {url} 49 | 50 | 51 | } 57 | > 58 | 59 |
    60 | )} 61 | {typeof url === 'string' && } 62 |
    63 | ) 64 | } 65 | -------------------------------------------------------------------------------- /ts/components/util/prettyTime.js: -------------------------------------------------------------------------------- 1 | // noinspection ES6ConvertVarToLetConst,JSUnresolvedReference 2 | 3 | "use strict" 4 | 5 | var map = { 6 | year: 31536000000, 7 | month: 2592000000, 8 | day: 86400000, 9 | hour: 3600000, 10 | minute: 60000, 11 | second: 1000, 12 | ms: 1 13 | } 14 | 15 | var short = { 16 | year: "y", 17 | month: "mo", 18 | day: "d", 19 | hour: "h", 20 | minute: "m", 21 | second: "s", 22 | ms: "ms" 23 | } 24 | 25 | export default function prettyTime(value, options) { 26 | options = options || {} 27 | 28 | if (typeof value === "string") { 29 | value = parseInt(value, 10) 30 | if (isNaN(value)) { 31 | throw new Error("Invalid value: " + value) 32 | } 33 | } else if (typeof value !== "number") { 34 | throw new Error("Invalid value: " + value) 35 | } 36 | 37 | value = Math.abs(value) 38 | 39 | var unit 40 | Object.keys(map).some(function (key) { 41 | var unitValue = map[key] 42 | unit = key 43 | if (value >= unitValue) { 44 | value = value / unitValue 45 | return true 46 | } 47 | }) 48 | 49 | if (typeof options.decimals === "number") { 50 | value = Number(value.toFixed(options.decimals)) 51 | } 52 | 53 | if (options.short) { 54 | unit = short[unit] 55 | } else if (value > 1 && unit !== "ms") { 56 | unit += "s" 57 | } 58 | 59 | return [value, unit].join(" ") 60 | } 61 | -------------------------------------------------------------------------------- /ts/components/util/util.ts: -------------------------------------------------------------------------------- 1 | export const convertUnixNanoToDate = (unixNano: number): Date => { 2 | const milliseconds = Number(unixNano / 1_000_000) // Convert to milliseconds 3 | 4 | return new Date(milliseconds) 5 | } 6 | 7 | import duration from 'dayjs/plugin/duration' 8 | import dayjs from 'dayjs' 9 | 10 | dayjs.extend(duration) 11 | 12 | // Format milliseconds into "2days 8hours 11:20" 13 | export const formatMillis = (millis: number): string => { 14 | const durationObj = dayjs.duration(millis) 15 | 16 | const minutes = durationObj.minutes().toString().padStart(2, '0') 17 | const seconds = durationObj.seconds().toString().padStart(2, '0') 18 | 19 | let duration = `${minutes}:${seconds}` 20 | 21 | if (durationObj.hours() > 0) { 22 | const unit = durationObj.hours() === 1 ? 'hour' : 'hours' 23 | duration = `${durationObj.hours()} ${unit} ${duration}` 24 | } 25 | if (durationObj.days() > 0) { 26 | const unit = durationObj.days() === 1 ? 'day' : 'days' 27 | duration = `${durationObj.days()} ${unit} ${duration}` 28 | } 29 | return duration 30 | } 31 | 32 | export const delay = (ms: number) => { 33 | return new Promise(resolve => setTimeout(resolve, ms)) 34 | } 35 | -------------------------------------------------------------------------------- /ts/components/window-listener.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { useEffect } from 'react' 3 | import { useIsSSR } from '@react-aria/ssr' 4 | 5 | import { uiState } from '@/components/state/ui-state' 6 | 7 | export const useWindowListener = () => { 8 | const ssr = useIsSSR() 9 | 10 | const handleMouseMove = (event: MouseEvent) => { 11 | uiState.cursorPos = { 12 | x: event.clientX, 13 | y: event.clientY, 14 | } 15 | } 16 | 17 | useEffect(() => { 18 | if (ssr) return 19 | window.addEventListener('mousemove', handleMouseMove) 20 | 21 | return () => { 22 | window.removeEventListener('mousemove', handleMouseMove) 23 | } 24 | }, [ssr]) 25 | 26 | return null 27 | } 28 | -------------------------------------------------------------------------------- /ts/config/fonts.ts: -------------------------------------------------------------------------------- 1 | import { Fira_Code as FontMono, Inter as FontSans } from 'next/font/google' 2 | 3 | export const fontSans = FontSans({ 4 | subsets: ['latin'], 5 | variable: '--font-sans', 6 | }) 7 | 8 | export const fontMono = FontMono({ 9 | subsets: ['latin'], 10 | variable: '--font-mono', 11 | }) 12 | -------------------------------------------------------------------------------- /ts/config/site.ts: -------------------------------------------------------------------------------- 1 | export type SiteConfig = typeof siteConfig 2 | 3 | export const siteConfig = { 4 | name: 'Live pprof', 5 | description: 'Monitor Go processes in real-time, launching in 1 second, not all day', 6 | navItems: [ 7 | { 8 | label: 'Home', 9 | href: '/', 10 | }, 11 | { 12 | label: 'About', 13 | href: '/about', 14 | }, 15 | ], 16 | links: { 17 | github: 'https://github.com/moderato-app/live-pprof', 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /ts/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import("next").NextConfig} */ 2 | const nextConfig = {} 3 | 4 | const withBundleAnalyzer = require('@next/bundle-analyzer')({ 5 | enabled: process.env.ANALYZE === 'true', 6 | }) 7 | 8 | module.exports = { 9 | ...withBundleAnalyzer(nextConfig), 10 | output: 'export', 11 | } 12 | 13 | // if you want to serve WEB with node, use webpack instead 14 | // const withTM = require("next-transpile-modules")(["echarts", "zrender"]); 15 | // 16 | // module.exports = withTM({}) 17 | -------------------------------------------------------------------------------- /ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "live-pprof", 3 | "version": "0.0.1", 4 | "private": false, 5 | "scripts": { 6 | "dev": "next dev --turbo", 7 | "build": "next build", 8 | "lint": "eslint . --ext .ts,.tsx -c .eslintrc.json --fix", 9 | "test": "vitest --run" 10 | }, 11 | "dependencies": { 12 | "@grpc/grpc-js": "^1.11.1", 13 | "@next/bundle-analyzer": "^14.2.8", 14 | "@nextui-org/accordion": "^2.0.38", 15 | "@nextui-org/button": "2.0.37", 16 | "@nextui-org/card": "^2.0.33", 17 | "@nextui-org/checkbox": "^2.1.4", 18 | "@nextui-org/chip": "^2.0.32", 19 | "@nextui-org/code": "2.0.32", 20 | "@nextui-org/dropdown": "^2.1.29", 21 | "@nextui-org/input": "2.2.4", 22 | "@nextui-org/kbd": "2.0.33", 23 | "@nextui-org/link": "2.0.34", 24 | "@nextui-org/listbox": "2.1.25", 25 | "@nextui-org/modal": "^2.0.39", 26 | "@nextui-org/navbar": "2.0.36", 27 | "@nextui-org/select": "^2.2.5", 28 | "@nextui-org/snippet": "2.0.41", 29 | "@nextui-org/spacer": "^2.0.32", 30 | "@nextui-org/switch": "2.0.33", 31 | "@nextui-org/system": "2.2.5", 32 | "@nextui-org/tabs": "^2.0.35", 33 | "@nextui-org/theme": "^2.2.9", 34 | "@react-aria/ssr": "3.9.4", 35 | "@react-aria/visually-hidden": "3.8.12", 36 | "clsx": "2.1.1", 37 | "dayjs": "^1.11.12", 38 | "echarts": "^5.5.1", 39 | "echarts-for-react": "^3.0.2", 40 | "framer-motion": "~11.1.1", 41 | "get-urls": "^12.1.0", 42 | "google-protobuf": "^3.21.4", 43 | "grpc-web": "^1.5.0", 44 | "lodash": "^4.17.21", 45 | "mitt": "^3.0.1", 46 | "next": "14.2.6", 47 | "next-themes": "^0.2.1", 48 | "pretty-bytes": "^6.1.1", 49 | "react": "18.3.1", 50 | "react-dom": "18.3.1", 51 | "valtio": "^1.13.2" 52 | }, 53 | "devDependencies": { 54 | "@iconify/react": "^5.0.2", 55 | "@testing-library/dom": "^10.4.0", 56 | "@testing-library/react": "^16.0.0", 57 | "@types/lodash": "^4.17.7", 58 | "@types/node": "20.5.7", 59 | "@types/react": "18.3.3", 60 | "@types/react-dom": "18.3.0", 61 | "@typescript-eslint/eslint-plugin": "7.2.0", 62 | "@typescript-eslint/parser": "7.2.0", 63 | "@vitejs/plugin-react": "^4.3.1", 64 | "autoprefixer": "10.4.19", 65 | "eslint": "^8.57.0", 66 | "eslint-config-next": "14.2.1", 67 | "eslint-config-prettier": "^8.2.0", 68 | "eslint-plugin-import": "^2.26.0", 69 | "eslint-plugin-jsx-a11y": "^6.4.1", 70 | "eslint-plugin-node": "^11.1.0", 71 | "eslint-plugin-prettier": "^5.1.3", 72 | "eslint-plugin-react": "^7.23.2", 73 | "eslint-plugin-react-hooks": "^4.6.0", 74 | "eslint-plugin-unused-imports": "^3.2.0", 75 | "jsdom": "^24.1.1", 76 | "postcss": "8.4.38", 77 | "prettier": "3.3.3", 78 | "tailwind-variants": "0.1.20", 79 | "tailwindcss": "3.4.3", 80 | "typescript": "5.0.4", 81 | "vitest": "^2.0.5" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ts/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /ts/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: false, 6 | singleQuote: false, 7 | trailingComma: 'none', 8 | bracketSpacing: true, 9 | jsxBracketSameLine: false, 10 | arrowParens: 'avoid', 11 | endOfLine: 'auto', 12 | importOrder: ['^[@]', '[./]'], 13 | importOrderSeparation: true, 14 | } 15 | -------------------------------------------------------------------------------- /ts/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moderato-app/live-pprof/573e0e771949f018ce486e86529bdc197a7c7327/ts/public/favicon.ico -------------------------------------------------------------------------------- /ts/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ts/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ts/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /ts/tailwind.config.js: -------------------------------------------------------------------------------- 1 | import { nextui } from "@nextui-org/theme" 2 | 3 | /** @type {import("tailwindcss").Config} */ 4 | module.exports = { 5 | content: [ 6 | "./components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./app/**/*.{js,ts,jsx,tsx,mdx}", 8 | "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}" 9 | ], 10 | theme: { 11 | extend: {} 12 | }, 13 | darkMode: "class", 14 | plugins: [nextui()] 15 | } 16 | -------------------------------------------------------------------------------- /ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /ts/types/index.ts: -------------------------------------------------------------------------------- 1 | import { SVGProps } from 'react' 2 | 3 | export type IconSvgProps = SVGProps & { 4 | size?: number 5 | } 6 | -------------------------------------------------------------------------------- /ts/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | 3 | import { defineConfig } from 'vitest/config' 4 | import react from '@vitejs/plugin-react' 5 | 6 | export default defineConfig({ 7 | plugins: [react()], 8 | test: { 9 | environment: 'jsdom', 10 | }, 11 | resolve: { 12 | alias: [{ find: '@', replacement: resolve(__dirname, '.') }], 13 | }, 14 | }) 15 | --------------------------------------------------------------------------------