github.com/grafana/pyroscope@v1.18.0/docs/sources/reference-server-api/index.template (about)

     1  ---
     2  description: Learn about the Pyroscope server API
     3  menuTitle: "Reference: Server API"
     4  title: Server HTTP API
     5  aliases:
     6    - ../configure-server/about-server-api/ # https://grafana.com/docs/pyroscope/latest/configure-server/about-server-api/
     7  weight: 650
     8  ---
     9  
    10  # Grafana Pyroscope server API
    11  
    12  ## Authentication
    13  
    14  Pyroscope doesn't include an authentication layer. Operators should use an authenticating reverse proxy for security.
    15  
    16  In multi-tenant mode, Pyroscope requires the X-Scope-OrgID HTTP header set to a string identifying the tenant.
    17  The authenticating reverse proxy handles this responsibility. For more information, refer to the [multi-tenancy documentation](https://grafana.com/docs/pyroscope/<PYROSCOPE_VERSION>/configure-server/about-tenant-ids/).
    18  
    19  
    20  ## Connect API
    21  
    22  The Pyroscope Connect API uses the [Connect protocol](https://connectrpc.com/), which provides a unified approach to building APIs that work seamlessly across multiple protocols and formats:
    23  
    24  - **Protocol Flexibility**: Connect APIs work over both HTTP/1.1 and HTTP/2, supporting JSON and binary protobuf encoding
    25  - **gRPC Compatibility**: Full compatibility with existing gRPC clients and servers while offering better browser and HTTP tooling support  
    26  - **Type Safety**: Generated from protobuf definitions, ensuring consistent types across client and server implementations
    27  - **Developer Experience**: Simpler debugging with standard HTTP tools like curl, while maintaining the performance benefits of protobuf
    28  
    29  The API definitions are available in the [`api/`](https://github.com/grafana/pyroscope/tree/main/api) directory of the Pyroscope repository, with protobuf schemas organized by service.
    30  
    31  Pyroscope APIs are categorized into two scopes:
    32  
    33  - **Public APIs** (`scope/public`): These APIs are considered stable. Breaking changes will be communicated in advance and include migration paths.
    34  - **Internal APIs** (`scope/internal`): These APIs are used for internal communication between Pyroscope components. They may change without notice and should not be used by external clients.
    35  
    36  ### Ingestion Path
    37  
    38  {{ .RenderAPIGroup "/push.v1.PusherService" }}
    39  
    40  ### Querying profiling data
    41  
    42  {{ .RenderAPIGroup "/querier.v1.QuerierService" }}
    43  
    44  
    45  ## Pyroscope Legacy HTTP API
    46  
    47  Grafana Pyroscope exposes an HTTP API for querying profiling data and ingesting profiling data from other sources.
    48  
    49  
    50  ### Ingestion
    51  
    52  There is one primary endpoint: `POST /ingest`.
    53  It accepts profile data in the request body and metadata as query parameters.
    54  
    55  The following query parameters are accepted:
    56  
    57  | Name               | Description                             | Notes                          |
    58  |:-------------------|:----------------------------------------|:-------------------------------|
    59  | `name`             | application name                        | required                       |
    60  | `from`             | UNIX time of when the profiling started | required                       |
    61  | `until`            | UNIX time of when the profiling stopped | required                       |
    62  | `format`           | format of the profiling data            | optional (default is `folded`) |
    63  | `sampleRate`       | sample rate used in Hz                  | optional (default is `100` Hz) |
    64  | `spyName`          | name of the spy used                    | optional                       |
    65  | `units`            | name of the profiling data unit         | optional (default is `samples` |
    66  | `aggregrationType` | type of aggregation to merge profiles   | optional (default is `sum`)    |
    67  
    68  
    69  `name` specifies application name. For example:
    70  ```
    71  my.awesome.app.cpu{env=staging,region=us-west-1}
    72  ```
    73  
    74  The request body contains profiling data, and the Content-Type header may be used alongside format to determine the data format.
    75  
    76  Some of the query parameters depend on the format of profiling data. Pyroscope currently supports three major ingestion formats.
    77  
    78  #### Text formats
    79  
    80  These formats handle simple ingestion of profiling data, such as `cpu` samples, and typically don't support metadata (for example, labels) within the format.
    81  All necessary metadata is derived from query parameters, and the format is specified by the `format` query parameter.
    82  
    83  **Supported formats:**
    84  
    85  - **Folded**: Also known as `collapsed`, this is the default format. Each line contains a stacktrace followed by the sample count for that stacktrace. For example:
    86  ```
    87  foo;bar 100
    88  foo;baz 200
    89  ```
    90  
    91  - **Lines**: Similar to `folded`, but it represents each sample as a separate line rather than aggregating samples per stacktrace. For example:
    92  ```
    93  foo;bar
    94  foo;bar
    95  foo;baz
    96  foo;bar
    97  ```
    98  
    99  #### The `pprof` format
   100  
   101  The `pprof` format is a widely used binary profiling data format, particularly prevalent in the Go ecosystem.
   102  
   103  When using this format, certain query parameters have specific behaviors:
   104  
   105  - **format**: This should be set to `pprof`.
   106  - **name**: This parameter contains the _prefix_ of the application name. Since a single request might include multiple profile types, the complete application name is formed by concatenating this prefix with the profile type. For instance, if you send CPU profiling data and set `name` to `my-app{}`, it is displayed in Pyroscope as `my-app.cpu{}`.
   107  - **units**, **aggregationType**, and **sampleRate**: These parameters are ignored. The actual values are determined based on the profile types present in the data (refer to the "Sample Type Configuration" section for more details).
   108  
   109  ##### Sample type configuration
   110  
   111  Pyroscope server inherently supports standard Go profile types such as `cpu`, `inuse_objects`, `inuse_space`, `alloc_objects`, and `alloc_space`. When dealing with software that generates data in `pprof` format, you may need to supply a custom sample type configuration for Pyroscope to interpret the data correctly.
   112  
   113  For an example Python script to ingest a `pprof` file with a custom sample type configuration, see **[this Python script](https://github.com/grafana/pyroscope/tree/main/examples/api/ingest_pprof.py).**
   114  
   115  To ingest `pprof` data with custom sample type configuration, modify your requests as follows:
   116  * Set Content-Type to `multipart/form-data`.
   117  * Upload the profile data in a form file field named `profile`.
   118  * Include the sample type configuration in a form file field named `sample_type_config`.
   119  
   120  A sample type configuration is a JSON object formatted like this:
   121  
   122  ```json
   123  {
   124    "inuse_space": {
   125      "units": "bytes",
   126      "aggregation": "average",
   127      "display-name": "inuse_space_bytes",
   128      "sampled": false
   129    },
   130    "alloc_objects": {
   131      "units": "objects",
   132      "aggregation": "sum",
   133      "display-name": "alloc_objects_count",
   134      "sampled": true
   135    },
   136    "cpu": {
   137      "units": "samples",
   138      "aggregation": "sum",
   139      "display-name": "cpu_samples",
   140      "sampled": true
   141    },
   142    // pprof supports multiple profiles types in one file,
   143    //   so there can be multiple of these objects
   144  }
   145  ```
   146  
   147  Explanation of sample type configuration fields:
   148  
   149  - **units**
   150    - Supported values: `samples`, `objects`, `bytes`
   151    - Description: Changes the units displayed in the frontend. `samples` = CPU samples, `objects` = objects in RAM, `bytes` = bytes in RAM.
   152  - **display-name**
   153    - Supported values: Any string.
   154    - Description: This becomes a suffix of the app name, e.g., `my-app.inuse_space_bytes`.
   155  - **aggregation**
   156    - Supported values: `sum`, `average`.
   157    - Description: Alters how data is aggregated on the frontend. Use `sum` for data to be summed over time (e.g., CPU samples, memory allocations), and `average` for data to be averaged over time (e.g., memory in-use objects).
   158  - **sampled**
   159    - Supported values: `true`, `false`.
   160    - Description: Determines if the sample rate (specified in the pprof file) is considered. Set to `true` for sampled events (e.g., CPU samples), and `false` for memory profiles.
   161  
   162  This configuration allows for customized visualization and analysis of various profile types within Pyroscope.
   163  
   164  #### JFR format
   165  
   166  This is the [Java Flight Recorder](https://openjdk.java.net/jeps/328) format, typically used by JVM-based profilers, also supported by our Java integration.
   167  
   168  When this format is used, some of the query parameters behave slightly different:
   169  * `format` should be set to `jfr`.
   170  * `name` contains the _prefix_ of the application name. Since a single request may contain multiple profile types, the final application name is created concatenating this prefix and the profile type. For example, if you send cpu profiling data and set `name` to `my-app{}`, it will appear in pyroscope as `my-app.cpu{}`.
   171  * `units` is ignored, and the actual units depends on the profile types available in the data.
   172  * `aggregationType` is ignored, and the actual aggregation type depends on the profile types available in the data.
   173  
   174  JFR ingestion support uses the profile metadata to determine which profile types are included, which depend on the kind of profiling being done. Currently supported profile types include:
   175  * `cpu` samples, which includes only profiling data from runnable threads.
   176  * `itimer` samples, similar to `cpu` profiling.
   177  * `wall` samples, which includes samples from any threads independently of their state.
   178  * `alloc_in_new_tlab_objects`, which indicates the number of new TLAB objects created.
   179  * `alloc_in_new_tlab_bytes`, which indicates the size in bytes of new TLAB objects created.
   180  * `alloc_outside_tlab_objects`, which indicates the number of new allocated objects outside any TLAB.
   181  * `alloc_outside_tlab_bytes`, which indicates the size in bytes of new allocated objects outside any TLAB.
   182  
   183  ##### JFR with labels
   184  
   185  In order to ingest JFR data with dynamic labels, you have to make the following changes to your requests:
   186  * use an HTTP form (`multipart/form-data`) Content-Type.
   187  * send the JFR data in a form file field called `jfr`.
   188  * send `LabelsSnapshot` protobuf message in a form file field called `labels`.
   189  
   190  ```protobuf
   191  message Context {
   192      // string_id -> string_id
   193      map<int64, int64> labels = 1;
   194  }
   195  message LabelsSnapshot {
   196    // context_id -> Context
   197    map<int64, Context> contexts = 1;
   198    // string_id -> string
   199    map<int64, string> strings = 2;
   200  }
   201  
   202  ```
   203  Where `context_id` is a parameter [set in async-profiler](https://github.com/pyroscope-io/async-profiler/pull/1/files#diff-34c624b2fbf52c68fc3f15dee43a73caec11b9524319c3a581cd84ec3fd2aacfR218)
   204  
   205  #### Examples
   206  
   207  Here's a sample code that uploads a very simple profile to pyroscope:
   208  
   209  {{"{{< code >}}"}}
   210  
   211  ```curl
   212  printf "foo;bar 100\n foo;baz 200" | curl \
   213  -X POST \
   214  --data-binary @- \
   215  'http://localhost:4040/ingest?name=curl-test-app&from=1615709120&until=1615709130'
   216  
   217  ```
   218  
   219  ```python
   220  import requests
   221  import urllib.parse
   222  from datetime import datetime
   223  
   224  now = round(datetime.now().timestamp()) / 10 * 10
   225  params = {'from': f'{now - 10}', 'name': 'python.example{foo=bar}'}
   226  
   227  url = f'http://localhost:4040/ingest?{urllib.parse.urlencode(params)}'
   228  data = "foo;bar 100\n" \
   229  "foo;baz 200"
   230  
   231  requests.post(url, data = data)
   232  ```
   233  
   234  {{"{{< /code >}}"}}
   235  
   236  
   237  Here's a sample code that uploads a JFR profile with labels to pyroscope:
   238  
   239  {{"{{< code >}}"}}
   240  
   241  ```curl
   242  curl -X POST \
   243    -F jfr=@profile.jfr \
   244    -F labels=@labels.pb  \
   245    "http://localhost:4040/ingest?name=curl-test-app&units=samples&aggregationType=sum&sampleRate=100&from=1655834200&until=1655834210&spyName=javaspy&format=jfr"
   246  ```
   247  
   248  {{"{{< /code >}}"}}
   249  
   250  
   251  ### Querying profile data
   252  
   253  There is one primary endpoint for querying profile data: `GET /pyroscope/render`.
   254  
   255  The search input is provided via query parameters.
   256  The output is typically a JSON object containing one or more time series and a flame graph.
   257  
   258  #### Query parameters
   259  
   260  Here is an overview of the accepted query parameters:
   261  
   262  | Name       | Description                                                                            | Notes                                                |
   263  |:-----------|:---------------------------------------------------------------------------------------|:-----------------------------------------------------|
   264  | `query`    | contains the profile type and label selectors                                          | required                                             |
   265  | `from`     | UNIX time for the start of the search window                                           | required                                             |
   266  | `until`    | UNIX time for the end of the search window                                             | optional (default is `now`)                          |
   267  | `format`   | format of the profiling data                                                           | optional (default is `json`)                         |
   268  | `maxNodes` | the maximum number of nodes the resulting flame graph will contain                     | optional (default is `max_flamegraph_nodes_default`) |
   269  | `groupBy`  | one or more label names to group the time series by (doesn't apply to the flame graph) | optional (default is no grouping)                    |
   270  
   271  ##### `query`
   272  
   273  The `query` parameter is the only required search input. It carries the profile type and any labels we want to use to narrow down the output.
   274  The format for this parameter is similar to that of a PromQL query and can be defined as:
   275  
   276  `<profile_type>{<label_name>="<label_value>", <label_name>="<label_value>", ...}`
   277  
   278  Here is a specific example:
   279  
   280  `process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="my_application_name"}`
   281  
   282  In a Kubernetes environment, a query could also look like:
   283  
   284  `process_cpu:cpu:nanoseconds:cpu:nanoseconds{namespace="dev", container="my_application_name"}`
   285  
   286  {{"{{% admonition type=\"note\" %}}"}}
   287  Refer to the [profiling types documentation](https://grafana.com/docs/pyroscope/<PYROSCOPE_VERSION>/configure-client/profile-types/) for more information and [profile-metrics.json](https://github.com/grafana/pyroscope/blob/main/public/app/constants/profile-metrics.json) for a list of valid profile types.
   288  {{"{{% /admonition %}}"}}
   289  
   290  ##### `from` and `until`
   291  
   292  The `from` and `until` parameters determine the start and end of the time period for the query.
   293  They can be provided in absolute and relative form.
   294  
   295  **Absolute time**
   296  
   297  This table details the options for passing absolute values.
   298  
   299  | Option                 | Example               | Notes              |
   300  |:-----------------------|:----------------------|:-------------------|
   301  | Date                   | `20231223`            | Format: `YYYYMMDD` |
   302  | Unix Time seconds      | `1577836800`          |                    |
   303  | Unix Time milliseconds | `1577836800000`       |                    |
   304  | Unix Time microseconds | `1577836800000000`    |                    |
   305  | Unix Time nanoseconds  | `1577836800000000000` |                    |
   306  
   307  **Relative time**
   308  
   309  Relative values are always expressed as offsets from `now`.
   310  
   311  | Option         | Example              |
   312  |:---------------|:---------------------|
   313  | 3 hours ago    | `now-3h`             |
   314  | 30 minutes ago | `now-30m`            |
   315  | 2 days ago     | `now-2d`             |
   316  | 1 week ago     | `now-7d` or `now-1w` |
   317  
   318  Note that a single offset has to be provided, values such as `now-3h30m` will not work.
   319  
   320  **Validation**
   321  
   322  The `from` and `until` parameters are subject to validation rules related to `max_query_lookback` and `max_query_length` server parameters.
   323  You can find more details on these parameters in the [limits section](https://grafana.com/docs/pyroscope/<PYROSCOPE_VERSION>/configure-server/reference-configuration-parameters#limits) of the server configuration docs.
   324  
   325  - If `max_query_lookback` is configured and`from` is before `now - max_query_lookback`, `from` will be set to `now - max_query_lookback`.
   326  - If `max_query_lookback` is configured and `until` is before `now - max_query_lookback` the query will not be executed.
   327  - If `max_query_length` is configured and the query interval is longer than this configuration, the query will no tbe executed.
   328  
   329  #### `format`
   330  
   331  The format can either be:
   332  - `json`, in which case the response will contain a JSON object
   333  - `dot`, in which case the response will be text containing a DOT representation of the profile
   334  
   335  See the [Query output](#query-output) section for more information on the response structure.
   336  
   337  #### `maxNodes`
   338  
   339  The `maxNodes` parameter truncates the number of elements in the profile response, to allow tools (for example, a frontend) to render large profiles efficiently.
   340  This is typically used for profiles that are known to have large stack traces.
   341  
   342  When no value is provided, the default is taken from the `max_flamegraph_nodes_default` configuration parameter.
   343  When a value is provided, it is capped to the `max_flamegraph_nodes_max` configuration parameter.
   344  
   345  #### `groupBy`
   346  
   347  The `groupBy` parameter impacts the output for the time series portion of the response.
   348  When a valid label is provided, the response contains as many series as there are label values for the given label.
   349  
   350  {{"{{% admonition type=\"note\" %}}"}}
   351  Pyroscope supports a single label for the group by functionality.
   352  {{"{{% /admonition %}}"}}
   353  
   354  ### Query output
   355  
   356  The output of the `/pyroscope/render` endpoint is a JSON object based on the following [schema](https://github.com/grafana/pyroscope/blob/80959aeba2426f3698077fd8d2cd222d25d5a873/pkg/og/structs/flamebearer/flamebearer.go#L28-L43):
   357  
   358  ```go
   359  type FlamebearerProfileV1 struct {
   360  	Flamebearer FlamebearerV1                  `json:"flamebearer"`
   361  	Metadata FlamebearerMetadataV1             `json:"metadata"`
   362  	Timeline *FlamebearerTimelineV1            `json:"timeline"`
   363  	Groups   map[string]*FlamebearerTimelineV1 `json:"groups"`
   364  }
   365  ```
   366  
   367  #### `flamebearer`
   368  
   369  The `flamebearer` field contains data in a form suitable for rendering a flame graph.
   370  Data within the `flamebearer` is organized in separate arrays containing the profile symbols and the sample values.
   371  
   372  #### `metadata`
   373  
   374  The `metadata` field contains additional information that is helpful to interpret the `flamebearer` data such as the unit (nanoseconds, bytes), sample rate and more.
   375  
   376  #### `timeline`
   377  
   378  The `timeline` field represents the time series for the profile.
   379  Pyroscope pre-computes the step interval (resolution) of the timeline using the query interval (`from` and `until`). The minimum step interval is 10 seconds.
   380  
   381  The raw profile sample data is down-sampled to the step interval (resolution) using an aggregation function. Currently only `sum` is supported.
   382  
   383  A timeline contains a start time, a list of sample values and the step interval:
   384  
   385  ```json
   386  {
   387    "timeline": {
   388      "startTime": 1577836800,
   389      "samples": [
   390        100,
   391        200,
   392        400
   393      ],
   394      "durationDelta": 10
   395    }
   396  }
   397  ```
   398  
   399  #### `groups`
   400  
   401  The `groups` field is only populated when grouping is requested by the `groupBy` query parameter.
   402  When this is the case, the `groups` field has an entry for every label value found for the query.
   403  
   404  This example groups by a cluster:
   405  
   406  ```json
   407  {
   408    "groups": {
   409      "eu-west-2": { "startTime": 1577836800, "samples": [ 200, 300, 500 ] },
   410      "us-east-1": { "startTime": 1577836800, "samples": [ 100, 200, 400 ] }
   411    }
   412  }
   413  ```
   414  
   415  ### Alternative query output
   416  
   417  When the `format` query parameter is `dot`, the endpoint responds with a [DOT format](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) data representing the queried profile.
   418  This can be used to create an alternative visualization of the profile.
   419  
   420  ### Example queries
   421  
   422  This example queries a local Pyroscope server for a CPU profile from the `pyroscope` service for the last hour.
   423  
   424  ```curl
   425  curl \
   426    'http://localhost:4040/pyroscope/render?query=process_cpu%3Acpu%3Ananoseconds%3Acpu%3Ananoseconds%7Bservice_name%3D%22pyroscope%22%7D&from=now-1h'
   427  ```
   428  
   429  Here is the same query made more readable:
   430  
   431  ```curl
   432  curl --get \
   433    --data-urlencode "query=process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name=\"pyroscope\"}" \
   434    --data-urlencode "from=now-1h" \
   435    http://localhost:4040/pyroscope/render
   436  ```
   437  
   438  Here is the same example in Python:
   439  
   440  ```python
   441  import requests
   442  
   443  application_name = 'my_application_name'
   444  query = f'process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="{application_name}"}'
   445  query_from = 'now-1h'
   446  url = f'http://localhost:4040/pyroscope/render?query={query}&from={query_from}'
   447  
   448  requests.get(url)
   449  ```
   450  
   451  See [this Python script](https://github.com/grafana/pyroscope/tree/main/examples/api/query.py) for a complete example.
   452  
   453  ## Profile CLI
   454  
   455  The `profilecli` tool can also be used to interact with the Pyroscope server API.
   456  The tool supports operations such as ingesting profiles, querying for existing profiles, and more.
   457  Refer to the [Profile CLI](https://grafana.com/docs/pyroscope/<PYROSCOPE_VERSION>/view-and-analyze-profile-data/profile-cli/) page for more information.