Create bring-grafana-dashboards-to-nr.mdx#23931
Create bring-grafana-dashboards-to-nr.mdx#23931mangulonr wants to merge 4 commits intonewrelic:developfrom
Conversation
|
Hi @mangulonr 👋 Thanks for your pull request! Your PR is in a queue, and a writer will take a look soon. We generally publish small edits within one business day, and larger edits within three days. Please ensure the propsed changes look good by building it first in your local environment. Refer to this contribution guide to get the site up and running in your local. If you really require a preview url, reach out to one of the writers and they will generate one for you. |
|
netlify build |
Philip-R-Beckwith
left a comment
There was a problem hiding this comment.
I would strongly suggest removing the large scripts from this doc.
While it may feel like we're helping customers by handing edge-cases, we're actually actively working against them.
If customers who don't want to use bash and/or are unfamiliar with bash are faced with these massive examples, it's much harder for them to get their own workflow up and running if we're giving them a wall of code.
What we're kind of doing with this huge example is writing for the non technical user. Which is a fallacy. We do have some non technical users, and for them, we need to put this endpoint behind a UI. But for our technical users, we have to assume that they have both the skills and the desire to take code snip-its and use them in their own workflow. By assuming that we wrote exactly the script that they will want, is to not understand the intended audience.
Almost half of this page is eaten up by scripts that our customer may not even want.
| ```bash | ||
| # Translate and upload all dashboards to New Relic (default, US region) | ||
| ./translate_dashboards.sh path/to/dashboards/ | ||
| ``` | ||
|
|
||
| **Script (`translate_dashboards.sh`):** | ||
|
|
||
| ```bash | ||
| #!/usr/bin/env bash | ||
| # translate_dashboards.sh | ||
| # Translates all Grafana dashboard JSON files in a directory to New Relic dashboards | ||
| # and uploads each to New Relic by default. | ||
| # | ||
| # Required env vars: | ||
| # NR_USER_KEY — Your New Relic user API key | ||
| # | ||
| # Optional env vars: | ||
| # ACCOUNT_ID — New Relic account ID to override the default query target for all dashboards. | ||
| # Required when UPLOAD=true (the default). | ||
| # REGION — "US" (default) or "EU" | ||
| # OUTPUT_DIR — Directory to save translated files (default: <input_dir>/translated) | ||
| # UPLOAD — Set to "false" to skip uploading and only save the translated JSON files locally. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # ── Configuration ──────────────────────────────────────────────────────────── | ||
| NR_USER_KEY="${NR_USER_KEY:?Please set NR_USER_KEY to your New Relic user API key}" | ||
| INPUT_DIR="${1:?Usage: $0 <path/to/dashboards/directory>}" | ||
| REGION="${REGION:-US}" | ||
| ACCOUNT_ID="${ACCOUNT_ID:-}" | ||
| UPLOAD="${UPLOAD:-true}" | ||
| OUTPUT_DIR="${OUTPUT_DIR:-${INPUT_DIR}/translated}" | ||
|
|
||
| if [[ "${REGION}" == "EU" ]]; then | ||
| TRANSLATOR_ENDPOINT="https://prometheus-api.eu.newrelic.com/api/v1/translate/dashboard/grafana" | ||
| NERDGRAPH_ENDPOINT="https://api.eu.newrelic.com/graphql" | ||
| else | ||
| TRANSLATOR_ENDPOINT="https://prometheus-api.newrelic.com/api/v1/translate/dashboard/grafana" | ||
| NERDGRAPH_ENDPOINT="https://api.newrelic.com/graphql" | ||
| fi | ||
|
|
||
| mkdir -p "${OUTPUT_DIR}" | ||
|
|
||
| # ── Warn early if upload is on but no account ID provided ───────────────────── | ||
| if [[ "${UPLOAD}" == "true" && -z "${ACCOUNT_ID}" ]]; then | ||
| echo "WARNING: ACCOUNT_ID is not set — dashboards will be saved locally only (upload skipped)." | ||
| UPLOAD="false" | ||
| fi | ||
|
|
||
| # ── Validate input ──────────────────────────────────────────────────────────── | ||
| shopt -s nullglob | ||
| JSON_FILES=("${INPUT_DIR}"/*.json) | ||
| shopt -u nullglob | ||
|
|
||
| if [[ ${#JSON_FILES[@]} -eq 0 ]]; then | ||
| echo "No JSON files found in: ${INPUT_DIR}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "Found ${#JSON_FILES[@]} dashboard(s) in: ${INPUT_DIR}" | ||
| echo "Output directory: ${OUTPUT_DIR}" | ||
| [[ "${UPLOAD}" == "true" ]] && echo "Upload: enabled (account: ${ACCOUNT_ID})" || echo "Upload: disabled (local files only)" | ||
| echo "" | ||
|
|
||
| # ── Translate each file ─────────────────────────────────────────────────────── | ||
| SUCCESS=0 | ||
| FAIL=0 | ||
|
|
||
| for JSON_FILE in "${JSON_FILES[@]}"; do | ||
| BASENAME=$(basename "${JSON_FILE}" .json) | ||
| OUTPUT_FILE="${OUTPUT_DIR}/${BASENAME}_translated.json" | ||
|
|
||
| echo "Translating: ${BASENAME}.json ..." | ||
|
|
||
| if [[ -n "${ACCOUNT_ID}" ]]; then | ||
| PAYLOAD=$(jq -c -n \ | ||
| --arg accountId "${ACCOUNT_ID}" \ | ||
| --slurpfile dashboard "${JSON_FILE}" \ | ||
| '{accountId: ($accountId | tonumber), dashboard: $dashboard[0]}') | ||
| else | ||
| PAYLOAD=$(jq -c -n \ | ||
| --slurpfile dashboard "${JSON_FILE}" \ | ||
| '{dashboard: $dashboard[0]}') | ||
| fi | ||
|
|
||
| if NR_DASHBOARD=$(curl -sf "${TRANSLATOR_ENDPOINT}" \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "x-api-key: ${NR_USER_KEY}" \ | ||
| -d "${PAYLOAD}" | jq '.dashboard'); then | ||
|
|
||
| echo "${NR_DASHBOARD}" > "${OUTPUT_FILE}" | ||
| echo " Saved → ${OUTPUT_FILE}" | ||
|
|
||
| # ── Upload (default: on) ──────────────────────────────────────────────────── | ||
| if [[ "${UPLOAD}" == "true" ]]; then | ||
| RESULT=$(curl -sf -X POST "${NERDGRAPH_ENDPOINT}" \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "API-Key: ${NR_USER_KEY}" \ | ||
| -d "$(jq -cn \ | ||
| --arg query 'mutation($accountId: Int!, $dashboard: DashboardInput!) { dashboardCreate(accountId: $accountId, dashboard: $dashboard) { entityResult { guid name } errors { description } } }' \ | ||
| --argjson variables "{\"accountId\": ${ACCOUNT_ID}, \"dashboard\": ${NR_DASHBOARD}}" \ | ||
| '{query: $query, variables: $variables}')" \ | ||
| | jq -r '.data.dashboardCreate.entityResult.name // "upload failed"') | ||
|
|
||
| echo " Uploaded → ${RESULT}" | ||
| fi | ||
|
|
||
| ((SUCCESS++)) | ||
| else | ||
| echo " ERROR: Translation failed for ${BASENAME}.json" | ||
| ((FAIL++)) | ||
| fi | ||
| done | ||
|
|
||
| # ── Summary ─────────────────────────────────────────────────────────────────── | ||
| echo "" | ||
| echo "────────────────────────────────────────" | ||
| echo "Done. Translated: ${SUCCESS} | Failed: ${FAIL}" | ||
| echo "Output directory: ${OUTPUT_DIR}" |
There was a problem hiding this comment.
Providing a large script like this isn't really documentation.
I haven't seen other places in our docs where we provide 100+ lines of code as documentation.
This really does pigeonhole our customers into using this authoritative script.
Instead of having them have to dig though this massive block to figure out how to use the endpoint, the examples should be the shortest amount of info necessary to understand how to use the endpoint.
If we want to proved THE script that we want customers to use... It should be built into an endpoint on our end, or we should provide the script in the top languages we'd expect customers to use. Python/ Javascript/ bash.
It's also strange that the rest of the examples are in collapsable blocks but this one is not.
There was a problem hiding this comment.
As commented, I 'm going to simplify the script.
Did Cloudsoft provide a Python version of the script?
Regarding the format, you're right. Either all of them or none of them should be included inside collapsable blocks. I will review it today, consider this version as an early draft.
| Translates one Grafana dashboard JSON file and uploads it to New Relic by default. | ||
|
|
||
| **Usage:** | ||
|
|
||
| **Required:** `NR_USER_KEY` always. `ACCOUNT_ID` is required when `UPLOAD=true` (the default). All other options are documented in the script header. | ||
|
|
||
| ```bash | ||
| # Translate and upload to New Relic (default, US region) | ||
| ./translate_dashboard.sh path/to/dashboard.json | ||
| ``` | ||
|
|
||
| **Script (`translate_dashboard.sh`):** | ||
|
|
||
| ```bash | ||
| #!/usr/bin/env bash | ||
| # translate_dashboard.sh | ||
| # Translates a single Grafana dashboard JSON to a New Relic dashboard | ||
| # and uploads it to New Relic by default. | ||
| # | ||
| # Required env vars: | ||
| # NR_USER_KEY — Your New Relic user API key | ||
| # | ||
| # Optional env vars: | ||
| # ACCOUNT_ID — New Relic account ID to override the default query target. | ||
| # Required when UPLOAD=true (the default). | ||
| # REGION — "US" (default) or "EU" | ||
| # UPLOAD — Set to "false" to skip uploading and only save the translated JSON locally. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # ── Configuration ──────────────────────────────────────────────────────────── | ||
| NR_USER_KEY="${NR_USER_KEY:?Please set NR_USER_KEY to your New Relic user API key}" | ||
| JSON_FILE="${1:?Usage: $0 <path/to/dashboard.json>}" | ||
| REGION="${REGION:-US}" | ||
| ACCOUNT_ID="${ACCOUNT_ID:-}" | ||
| UPLOAD="${UPLOAD:-true}" | ||
|
|
||
| if [[ "${REGION}" == "EU" ]]; then | ||
| TRANSLATOR_ENDPOINT="https://prometheus-api.eu.newrelic.com/api/v1/translate/dashboard/grafana" | ||
| NERDGRAPH_ENDPOINT="https://api.eu.newrelic.com/graphql" | ||
| else | ||
| TRANSLATOR_ENDPOINT="https://prometheus-api.newrelic.com/api/v1/translate/dashboard/grafana" | ||
| NERDGRAPH_ENDPOINT="https://api.newrelic.com/graphql" | ||
| fi | ||
|
|
||
| # ── Build request payload ───────────────────────────────────────────────────── | ||
| if [[ -n "${ACCOUNT_ID}" ]]; then | ||
| PAYLOAD=$(jq -c -n \ | ||
| --arg accountId "${ACCOUNT_ID}" \ | ||
| --slurpfile dashboard "${JSON_FILE}" \ | ||
| '{accountId: ($accountId | tonumber), dashboard: $dashboard[0]}') | ||
| else | ||
| PAYLOAD=$(jq -c -n \ | ||
| --slurpfile dashboard "${JSON_FILE}" \ | ||
| '{dashboard: $dashboard[0]}') | ||
| fi | ||
|
|
||
| # ── Translate ───────────────────────────────────────────────────────────────── | ||
| echo "Translating: ${JSON_FILE} ..." | ||
|
|
||
| NR_DASHBOARD=$(curl -sf "${TRANSLATOR_ENDPOINT}" \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "x-api-key: ${NR_USER_KEY}" \ | ||
| -d "${PAYLOAD}" | jq '.dashboard') | ||
|
|
||
| OUTPUT_FILE="${JSON_FILE%.json}_translated.json" | ||
| echo "${NR_DASHBOARD}" > "${OUTPUT_FILE}" | ||
| echo "Translated dashboard saved to: ${OUTPUT_FILE}" | ||
|
|
||
| # ── Upload (default: on) ────────────────────────────────────────────────────── | ||
| if [[ "${UPLOAD}" == "true" ]]; then | ||
| if [[ -z "${ACCOUNT_ID}" ]]; then | ||
| echo "WARNING: ACCOUNT_ID is not set — skipping upload. Set ACCOUNT_ID to enable automatic upload." | ||
| else | ||
| echo "Uploading dashboard to New Relic (account: ${ACCOUNT_ID}) ..." | ||
|
|
||
| RESULT=$(curl -sf -X POST "${NERDGRAPH_ENDPOINT}" \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "API-Key: ${NR_USER_KEY}" \ | ||
| -d "$(jq -cn \ | ||
| --arg query 'mutation($accountId: Int!, $dashboard: DashboardInput!) { dashboardCreate(accountId: $accountId, dashboard: $dashboard) { entityResult { guid name } errors { description } } }' \ | ||
| --argjson variables "{\"accountId\": ${ACCOUNT_ID}, \"dashboard\": ${NR_DASHBOARD}}" \ | ||
| '{query: $query, variables: $variables}')" \ | ||
| | jq -r '.data.dashboardCreate') | ||
|
|
||
| echo "Upload result:" | ||
| echo "${RESULT}" | jq '.' | ||
| fi | ||
| else | ||
| echo "UPLOAD=false — dashboard saved locally only, not created in New Relic." | ||
| fi | ||
| ``` |
There was a problem hiding this comment.
Same comments here, it's activly working against the customer to provide such large examples.
It makes them have to dig though this code to pull out the pieces they want to use to get their workflow.
They may not be using bash, they may want to use python, javascript, or any other number of scripting languages.
So providing them a massive script, forces them to either, dig though this to figure out what's the minimal information they need which may be hard if they aren't well versed in bash, or may force them to use bash so they don't have to edit this script.
Neither of these situations are ideal, especially considering that this script isn't the only or the best use-case for our endpoint. Customers may want to set up script that pulls their grafana dashboards straight from the grafana API. It's easier to plug in small examples into the script that they want to write, rather than wrangle this large block. Especially if they'd rather use any other language than a bash script.
There was a problem hiding this comment.
Kind of agree, this doc is just the 1st version I created based on your original.
Scripts needs to be shorter and more simple
|
|
||
| There are two ways to translate your Grafana dashboards: | ||
|
|
||
| | | [Option 1: Scripts](#scripts) | [Option 2: Manual API request](#manual-api) | | ||
| |---|---|---| | ||
| | **Best for** | Translating one or many dashboards quickly | One-off translations, custom integrations | | ||
| | **Requirements** | `curl`, `jq`, bash | `curl`, `jq` | | ||
| | **Control** | Automated looping, uploads to NR by default | Full control over each request | | ||
| | **Output** | Uploads to NR by default; set `UPLOAD=false` to save locally only | Requires a second `curl` call to NerdGraph to upload to NR | |
There was a problem hiding this comment.
This doesn't make sense. Customer can translate their dashboards using python, javascript, groovy, java, rust, go, anything. We're telling them that the only option they have is to use our curated, AI script, and it's simply not true.
We should not tell customers that they have to use these scripts.
- They can use any language that can submit a post to our endpoint
- The scripts on this page are very pigeonholed into one use case, even though our customers may have tons of different needs.
We're also calling the smaller examples "manual" which I don't understand.
There was a problem hiding this comment.
I've removed the table to simplify the doc as it is repeating info already provided, I will look for alternatives instead of manual
| Before using this API, you'll need: | ||
|
|
||
| * A [New Relic user API key](/docs/apis/get-started/intro-apis/types-new-relic-api-keys#user-api-key) | ||
| * Your Grafana dashboard exported as JSON (in Grafana: Settings → JSON Model → Copy to Clipboard) |
There was a problem hiding this comment.
This isn't necessarily true if the customer writes a script to fetch their dashboard from Grafana's API
There was a problem hiding this comment.
Thanks, you're correct. Item removed
| * A [New Relic user API key](/docs/apis/get-started/intro-apis/types-new-relic-api-keys#user-api-key) | ||
| * Your Grafana dashboard exported as JSON (in Grafana: Settings → JSON Model → Copy to Clipboard) | ||
| * Your New Relic account ID (if you want to override the default account) | ||
| * [`curl`](https://curl.se/) and [`jq`](https://stedolan.github.io/jq/) installed (required for the scripts and curl examples) |
There was a problem hiding this comment.
Is is untrue if the customer wishes to use anything other than these scripts.
If they use a different language, this isn't true
And if they wish to use bash but not curl, and JQ there's other libraries that they could use instead.
These are only required if they use our examples exactly as they are.
There was a problem hiding this comment.
Yes, these requirements should only be commented in the scripts section.
|
|
||
| ## Option 1: Scripts [#scripts] | ||
|
|
||
| Copy and paste these scripts directly onto your laptop. Both scripts require `curl` and `jq` to be installed, and accept configuration via environment variables. |
There was a problem hiding this comment.
Copy and paste these scripts directly onto your laptop.
It feels a bit weird that we're being this verbose about how to use the script, but also not providing further steps on how to run bash.
I think we can omit this callout with the assumption that our customers are familiar with bash scripts.
There was a problem hiding this comment.
Removed, now we just mention the commands required and the config/env variables capability
|
|
||
| Copy and paste these scripts directly onto your laptop. Both scripts require `curl` and `jq` to be installed, and accept configuration via environment variables. | ||
|
|
||
| Both scripts **upload translated dashboards to New Relic automatically by default** via the NerdGraph API, and also save the translated JSON to a local file. Set `UPLOAD=false` to skip the upload and only save the translated JSON locally without creating it in your New Relic account. |
There was a problem hiding this comment.
It's strange that we are always writing files locally.
We have an option UPLOAD=false but not one to skip writing the files to the local drive?
There was a problem hiding this comment.
I assume so.
Is this a problem?
Should we delete the file after being uploaded?
|
|
||
| --- | ||
|
|
||
| ## Option 2: Manual API request [#manual-api] |
There was a problem hiding this comment.
Why are we calling these examples of automation manual?
There was a problem hiding this comment.
Both can be considered as manual, correct, let me rephrase it
| } | ||
| ``` | ||
|
|
||
| ### Examples [#manual-examples] |
There was a problem hiding this comment.
#manual-examples
I wouldn't call this section manual.
| <img | ||
| title="Translator action item example" | ||
| alt="Action Item Example" | ||
| src="/images/grafana_dashboard_translator_action_items.webp" |
There was a problem hiding this comment.
This image is listed, but I'm not seeing it as a part of the PR.
Is it already included?
There was a problem hiding this comment.
It is pending, the PR is just an early draft, I need to add the image and the PromQL improvements to it
|
|
||
| --- | ||
|
|
||
| ## Grafana and New Relic widget types |
There was a problem hiding this comment.
If we keep the long scripts, I'd move this to the top of the doc so it's not quite so buried.
|
|
||
| --- | ||
|
|
||
| ## Troubleshoot translation errors [#troubleshooting] |
There was a problem hiding this comment.
If we keep the long scripts, I'd move this to the top of the doc so it's not quite so buried.
There was a problem hiding this comment.
The doc should be much shorter, so no need IMO to move this section
2nd draft version
|
Please, don't merge the PR until confirmed |
|
netlify build fork |
1 similar comment
|
netlify build fork |
Please follow conventional commit standards
in your commit messages and pull request title.
Give us some context
links to related docs, screenshots, etc.