{"id":19184036,"url":"https://github.com/cryostatio/jfr-datasource","last_synced_at":"2025-08-20T04:31:58.020Z","repository":{"id":37791287,"uuid":"184753412","full_name":"cryostatio/jfr-datasource","owner":"cryostatio","description":"JFR Datasource for Grafana","archived":false,"fork":false,"pushed_at":"2024-12-09T20:05:44.000Z","size":2439,"stargazers_count":48,"open_issues_count":7,"forks_count":13,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-12-09T21:20:25.716Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cryostatio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-03T12:41:47.000Z","updated_at":"2024-12-09T20:05:41.000Z","dependencies_parsed_at":"2024-03-18T21:04:15.650Z","dependency_job_id":"c6db7bd1-d695-4ff3-8ca4-c305942249a8","html_url":"https://github.com/cryostatio/jfr-datasource","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryostatio%2Fjfr-datasource","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryostatio%2Fjfr-datasource/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryostatio%2Fjfr-datasource/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cryostatio%2Fjfr-datasource/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cryostatio","download_url":"https://codeload.github.com/cryostatio/jfr-datasource/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230394228,"owners_count":18218707,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T11:05:56.841Z","updated_at":"2024-12-19T07:06:09.579Z","avatar_url":"https://github.com/cryostatio.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jfr-datasource\n\n[![Quay Repository](https://quay.io/repository/cryostat/jfr-datasource/status \"Quay Repository\")](https://quay.io/repository/cryostat/jfr-datasource)\n\n![Build Status](https://github.com/cryostatio/jfr-datasource/actions/workflows/ci.yaml/badge.svg)\n\nThis demonstrates how a simple JSON data source can be used in Grafana to read the events from a JFR file.\n\n## Usage\n\n### Dependencies\n\nFor native image support, GraalVM for Java 21 is needed with the environment variable `GRAALVM_HOME` set to its path. It can be downloaded from:\n```\nhttps://github.com/graalvm/graalvm-ce-builds/releases\n```\n\nAfter downloading, run\n```bash\n/path/to/graal-install/bin/gu install native-image\n```\n\n`libz.a` is also required to complete native image builds. On Fedora, `dnf install zlib-devel`.\n\nFor containers, podman is required. Installation instructions are here:\n```\nhttps://podman.io/getting-started/installation.html\n```\n\n### Build and run locally\n\nThis project uses [Quarkus](https://quarkus.io), which can produce a JAR to run in a JVM (JDK 21+), or an executable native image.\n\nTo build a JAR:\n```bash\n./mvnw clean verify\n```\nTo build a native image instead:\n```bash\n./mvnw -Pnative clean verify\n```\nNative image builds may use more than 4G of RAM to finish.\n\nTo build a native image within a container, for a consistent environment:\n```bash\n./mvnw -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman \\\n-Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21 \\\nclean verify\n```\n\n#### Run the server\n\nIf you built a JAR:\n```bash\njava -jar target/quarkus-app/quarkus-run.jar\n```\nIf you built a native image:\n```bash\n./target/jfr-datasource-*-runner\n```\n\n### Run Grafana\n\n- Install `SimpleJson` data source if not already installed via\n```bash\ngrafana-cli --pluginsDir \u003cpath-to-your-plugins-directory\u003e plugins install grafana-simple-json-datasource\n```\n- Add a `SimpleJson` data source\n- Set the URL to the `jfr-datasource` (default: `http://localhost:8080`)\n- Create a panel that pulls from the data source and plots a timeseries\n\n### Building a container image\n\nThis project comes with a Dockerfile to produce a container image with the native image result.\n\n```bash\npodman build -f src/main/docker/Dockerfile.native -t quay.io/cryostat/jfr-datasource .\n```\n\nTo produce a container image of the JVM mode result:\n```bash\npodman build -f src/main/docker/Dockerfile.jvm -t quay.io/cryostat/jfr-datasource .\n```\n\n## API\n\n### JFR Endpoints\n\n#### GET /\n\nResponds with 200 OK. Used to verify if the server is available.\n\nCURL Example\n```bash\n$ curl \"localhost:8080/\"\n```\n\n#### POST /upload\n\nExpects a JFR file upload. Used to upload a JFR file to the server. Responds with the uploaded filename.\n\nIf `overwrite` query parameter is set to `true`, the uploaded file will overwrite the existing one with the same name.\n\nThe webserver sets a default maximum file upload size of 10GB\n(`application.properties`: `quarkus.http.limits.max-body-size=10G`).\nThis can be overridden on a deployed instance by setting the environment variable\n`QUARKUS_HTTP_LIMITS_MAX_BODY_SIZE` and restarting the instance.\n\nCURL Example\n```bash\n$ curl -F \"file=@/home/user/some-file.jfr\" \"localhost:8080/upload\"\n```\n\nIt is also possible to bypass this webserver HTTP body size limit by copying\nthe large JFR file directly into the webserver's filesystem storage location.\nThis location is defined as\n(`application.properties`: `quarkus.http.body.uploads-directory=${java.io.tmpdir}${file.separator}jfr-file-uploads`),\nor `/tmp/jfr-file-uploads`. The following example assumes that the logged in\nuser has sufficient permissions and that the `jfr-datasource` container has\nan OpenShift Service and Route exposing it to traffic from outside the cluster.\n\n`oc` and CURL Example\n```bash\n$ oc cp my-large-file.jfr cryostat-sample-79cc897c8-smcrg:/tmp/jfr-file-uploads/my-large-file.jfr -c cryostat-sample-jfr-datasource\n$ curl -X POST --data \"my-large-file.jfr\" \"https://cryostat-sample-jfr-datasource-myproject.apps-crc.testing/set\"\n```\n\n#### POST /set\n\nSets a JFR file for querying requests. Expects file name specified via POST body.\n\nCURL Example\n```bash\n$ curl -X POST --data \"some-file\" \"localhost:8080/set\"\n```\n\n#### POST /load\n\nExpects a JFR file upload. Performs `Upload` and `Set` in sequence. Responds with the uploaded and selected filename.\n\nIf `overwrite` query parameter is set to `true`, the uploaded file will overwrite the existing one with the same name.\n\nThe webserver sets a default maximum file upload size. If the file to be\nuploaded exceeds this size then either the limit can be raised or the `/load`\noperation can be decomposed into two steps and the size limit worked around.\nSee the documentation for `POST /upload` for further detail.\n\nCURL Example\n```bash\n$ curl -F \"file=@/home/user/some-file.jfr\" \"localhost:8080/load\"\n```\n\n#### GET /list\n\nLists files available for `Set`.\nIf a file is currently `Set`, it is highlighted with enclosing double asterisks `**\u003cfilename\u003e.jfr**`\n\nCURL Example\n```bash\n$ curl \"localhost:8080/list\"\n\nfile1.jfr\nfile2.jfr\n**setFile.jfr**\n```\n\n#### GET /current\n\nResponds with the name of the currently `Set` file.\n\nCURL Example\n```bash\n$ curl \"localhost:8080/current\"\n\nsetFile.jfr\n```\n\n#### DELETE /delete\n\nDeletes an individual JFR file. Expects file name specified via DELETE body.\nIf the specified file was `Set`, then it is unset.\n\nCURL Example\n```bash\n$ curl -X DELETE --data \"some-file\" \"localhost:8080/delete\"\n```\n\n#### DELETE /delete_all\n\nDelete all JFR files.\n\nCURL Example\n```bash\n$ curl -X DELETE \"localhost:8080/delete_all\"\n```\n\n### Query Endpoints\n\nThese endpoints match those used by the [Grafana Simple JSON datasource](https://grafana.com/grafana/plugins/grafana-simple-json-datasource/).\n\n#### POST /search\n\nResponds with a JSON array containing selectable values of an event field (e.g. `jdk.ObjectAllocationSample.objectClass`) specified in the JSON body's `target` field. Used to define available selections for [dashboard variables](https://grafana.com/docs/grafana/v7.5/variables/).\n\nIf `target` is set to `*`, responds with all selectable event fields.\n\n\nCURL Example\n```bash\n$ curl -X POST --data '{ \"target\": \"jdk.ObjectAllocationSample.objectClass\" }' \"localhost:8080/search\"\n```\n\n\n#### POST /query\n\nResponds with a JSON array containing data points for a query. The query body format matches that of the Grafana Simple JSON datasource.\n\nThe `target` field can have parameters to filter matching data points If there is no parameter, no matching is performed. If a parameter is specified with \"*\", matching is done for all possible value of that parameter.\n\nCURL Example\n```bash\n$ curl -X POST --data '{ \"target\": \"jdk.ObjectAllocationSample.weight?objectClass=java.util.HashSet\", ...}' \"localhost:8080/query\"\n```\n\n## Supported JFR Events\n\nThis is a list of event attributes which work 'out-of-the-box' with this datasource. These are generally speaking any numerical timeseries-like event.\n\n```\njdk.ActiveRecording.endTime\njdk.ActiveRecording.recordingDuration\njdk.ActiveRecording.recordingStart\n\njdk.BiasedLockClassRevocation.duration\njdk.BiasedLockRevocation.duration\njdk.BiasedLockSelfRevocation.duration\n\njdk.ClassLoaderStatistics.anonymousBlockSize\njdk.ClassLoaderStatistics.anonymousChunkSize\njdk.ClassLoaderStatistics.anonymousClassCount\njdk.ClassLoaderStatistics.blockSize\njdk.ClassLoaderStatistics.chunkSize\njdk.ClassLoaderStatistics.classCount\n\njdk.ClassLoadingStatistics.loadedClassCount\n\njdk.CodeCacheConfiguration.expansionSize\njdk.CodeCacheConfiguration.initialSize\njdk.CodeCacheConfiguration.minBlockLength\njdk.CodeCacheConfiguration.nonNMethodSize\njdk.CodeCacheConfiguration.nonProfiledSize\njdk.CodeCacheConfiguration.profiledSize\njdk.CodeCacheConfiguration.reservedSize\n\njdk.CodeSweeperStatistics.methodReclaimedCount\njdk.CodeSweeperStatistics.peakFractionTime\njdk.CodeSweeperStatistics.peakSweepTime\njdk.CodeSweeperStatistics.sweepCount\njdk.CodeSweeperStatistics.totalSweepTime\n\njdk.CompilerConfiguration.threadCount\n\njdk.CompilerStatistics.compileCount\njdk.CompilerStatistics.bailoutCount\njdk.CompilerStatistics.invalidatedCount\njdk.CompilerStatistics.osrCompileCount\njdk.CompilerStatistics.standardCompileCount\njdk.CompilerStatistics.osrBytesCompiled\njdk.CompilerStatistics.standardBytesCompiled\njdk.CompilerStatistics.nmetodsSize\njdk.CompilerStatistics.nmetodCodeSize\njdk.CompilerStatistics.peakTimeSpent\njdk.CompilerStatistics.totalTimeSpent\n\njdk.CPUInformation.sockets\njdk.CPUInformation.cores\njdk.CPUInformation.hwThreads\n\njdk.CPULoad.jvmSystem\njdk.CPULoad.jvmUser\njdk.CPULoad.machineTotal\n\njdk.CPUTimestampCounter.osFrequency\njdk.CPUTimestampCounter.fastTimeFrequency\n\njdk.DataLoss.amount\njdk.DataLoss.total\n\njdk.ExceptionStatistics.throwables\n\njdk.GCConfiguration\njdk.GCHeapConfiguration\njdk.GCSurvivorConfiguration\njdk.GCTLABConfiguration\n\njdk.G1EvacuationOldStatistics\njdk.G1EvacuationYoungStatistics\n\njdk.JavaThreadStatistics.accumulatedCount\njdk.JavaThreadStatistics.activeCount\njdk.JavaThreadStatistics.daemonCount\njdk.JavaThreadStatistics.peakCount\n\njdk.YoungGenerationConfiguration\n\n\njdk.MetaspaceGCThreshold\n\njdk.JVMInformation\n\njdk.PhysicalMemory\n\njdk.ThreadContextSwitchRate\n\njdk.ObjectAllocationSample.eventThread\njdk.ObjectAllocationSample.stackTrace\njdk.ObjectAllocationSample.objectClass\njdk.ObjectAllocationSample.weight\n```\n\n### Unsupported JFR Events\n\nThis is a list of events which have no attributes that work out-of-the-box or no relevant attributes when visualized in Grafana.\n\n```\njdk.ActiveSetting\njdk.AllocationRequiringGC\njdk.BooleanFlag\njdk.BooleanFlagChanged\njdk.ClassDefine\njdk.ClassLoad\njdk.ClassUnload\njdk.CodeCacheFull\njdk.CodeCacheStatistics\njdk.CodeSweeperConfiguration\n** jdk.Compilation\njdk.CompilationFailure\n** jdk.CompilerInlining\njdk.CompilerPhase\njdk.ConcurrentModeFailure\njdk.DoubleFlag\njdk.DoubleFlagChanged\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcryostatio%2Fjfr-datasource","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcryostatio%2Fjfr-datasource","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcryostatio%2Fjfr-datasource/lists"}