{"id":20317533,"url":"https://github.com/dynatrace/backstage-plugin","last_synced_at":"2026-03-05T13:12:26.959Z","repository":{"id":228490831,"uuid":"700704351","full_name":"Dynatrace/backstage-plugin","owner":"Dynatrace","description":"Dynatrace Backstage Plugin","archived":false,"fork":false,"pushed_at":"2025-04-03T18:22:12.000Z","size":4656,"stargazers_count":29,"open_issues_count":16,"forks_count":5,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-03T19:29:03.684Z","etag":null,"topics":["backstage","developer-tools","plugins"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dynatrace.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2023-10-05T06:09:42.000Z","updated_at":"2025-03-26T01:15:17.000Z","dependencies_parsed_at":"2024-11-07T16:18:19.362Z","dependency_job_id":"ce71c9b2-9261-4274-8e7b-7deb227e0a0f","html_url":"https://github.com/Dynatrace/backstage-plugin","commit_stats":{"total_commits":243,"total_committers":19,"mean_commits":"12.789473684210526","dds":0.51440329218107,"last_synced_commit":"d602fa7705ed5343872f59432c3da4398fa73c40"},"previous_names":["dynatrace/backstage-plugin"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynatrace%2Fbackstage-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynatrace%2Fbackstage-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynatrace%2Fbackstage-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynatrace%2Fbackstage-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dynatrace","download_url":"https://codeload.github.com/Dynatrace/backstage-plugin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247601447,"owners_count":20964864,"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":["backstage","developer-tools","plugins"],"created_at":"2024-11-14T18:32:59.632Z","updated_at":"2026-03-05T13:12:26.950Z","avatar_url":"https://github.com/Dynatrace.png","language":"TypeScript","readme":"# Dynatrace Backstage Plugins\n\n_Context-rich observability and security insights at hand_ - The Dynatrace\nBackstage plugins enable you to fetch observability and security data from\n[Dynatrace](https://dynatrace.com/) to be displayed at software components\nmanaged in your\n[Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/).\nThe data is in tabular format with smart links to Dynatrace Apps for deeper\nanalysis and root cause investigation in case of a related problem or security\nvulnerability.\n\nThe plugins support Kubernetes entities by default. This means that it comes\nwith a pre-configured query for Kubernetes deployments and a dedicated component\nfor data representation.\n\nThis repository contains a complete Backstage installation at its root, with the\nindividual plugins in the `plugins` directory. Backstage is configured to\ninclude the plugins so you can start the app and see them in action.\n\n**Table of contents:**\n\n- [Overview](#overview)\n- [Getting Started](#getting-started)\n- [Additional Features](#additional-features)\n- [E2E Testing](#e2e-testing)\n- [Contributing](#contributing)\n\n## Overview\n\nThree plugins are required to fetch and visualize the data from Dynatrace:\n\n- [DQL](./plugins/dql/README.md) - A plugin showing DQL query results from\n  Dynatrace in Backstage.\n- [DQL Backend](./plugins/dql-backend/README.md) - The backend for the DQL\n  plugin.\n- [DQL Common](./plugins/dql-common/README.md) - Common functionality shared\n  between the DQL frontend and backend plugin.\n\nWith the Backstage plugins, the Backstage Software Catalog component can be\nassociated with real-time monitoring data. The screenshot shows three Kubernetes\ndeployments of the `easytrade-frontend` component running in different\nnamespaces, i.e., `development`, `hardening`, and `production`. The table\nprovides smart links for more details about the workload and logs in Dynatrace.\n\n![Kubernetes deployments monitored by Dynatrace](/docs/images/backstage_dynatrace_plugin.png 'Kubernetes deployments monitored by Dynatrace')\n\n\u003e While Kubernetes deployments are supported by default, any data can be fetched\n\u003e from Dynatrace and displayed in Backstage. See below how to configure\n\u003e [custom queries](#custom-queries).\n\n## Getting Started\n\nNext are the instructions to install, integrate, configure, and run the\nDyantrace Backstage plugins.\n\n### Install Plugins\n\n\u003e We are publishing our packages to NPM and removed the release candidate\n\u003e (v1.0.0-rc1) packages from the GitHub registry. If you were using the\n\u003e v1.0.0-rc1 packages, please update your `.yarnrc.yml` correspondingly.\n\nInstall the DQL plugins into Backstage:\n\n```bash\nyarn --cwd packages/app add @dynatrace/backstage-plugin-dql\nyarn --cwd packages/backend add @dynatrace/backstage-plugin-dql-backend\nyarn --cwd packages/backend add @dynatrace/backstage-plugin-dql-common\n```\n\n### Integrate the `EntityDqlQueryCard`\n\nAdd the DQL plugin to the respective component type pages in your\n`packages/app/src/components/catalog/EntityPage.tsx`:\n\n```tsx\n\u003cEntityDqlQueryCard\n  title=\"Kubernetes Deployments\"\n  queryId=\"dynatrace.kubernetes-deployments\"\n/\u003e\n```\n\nSee the `EntityPage.tsx` file in this repository\n(`packages/app/src/components/catalog/EntityPage.tsx`) for a full example.\n\n### Integrate the DQL Backend Plugin\n\nAdd the DQL backend plugin to in `packages/backend/src/index.ts`:\n\n```ts\nconst backend = createBackend();\n...\nbackend.add(import('@dynatrace/backstage-plugin-dql-backend'));\n...\n```\n\nSee the `index.ts` file in this repository (`packages/backend/src/index.ts`) for\na full example.\n\n### Add Dynatrace Environment Connection\n\nBefore configuring a Dynatrace connection, an OAuth 2.0 client is required.\n\n\u003cdetails\u003e\n  \u003csummary\u003eHow to create an OAuth 2.0 client\u003c/summary\u003e\n\n1. In Dynatrace, go to\n   [Account Management](https://docs.dynatrace.com/docs/manage/account-management).\n2. Select **Identity \u0026 access management** \u003e **OAuth clients**.\n3. Select **Create client**.\n4. Enter a client description and the user email.\n5. Select at least the following scopes.\n   - `storage:buckets:read`\n   - `storage:entities:read`\n   - `storage:events:read`\n   - `storage:metrics:read`\n   - `storage:security.events:read`\n6. Scroll down and select **Create client**.\n7. Copy your client ID, client secret, and Dynatrace account URN. These settings\nare required for the Backstage plugin\n[configuration](https://github.com/Dynatrace/backstage-plugin?tab=readme-ov-file#add-dynatrace-environment-connection).\n\u003c/details\u003e\n\nCreate or update the `app-config.local.yaml` file (excluded by `.gitignore`)\nconfiguring the connection to the Dynatrace environment:\n\n#### Using OAuth client credentials\n\n```yaml\ndynatrace:\n  environments:\n    - name: xxxxxxxx\n      url: https://xxxxxxxx.apps.dynatrace.com\n      tokenUrl: https://sso.dynatrace.com/sso/oauth2/token\n      accountUrn: \u003caccountUrn\u003e\n      clientId: \u003cclientId\u003e\n      clientSecret: \u003cclientSecret\u003e\n```\n\n#### Using Dynatrace Platform Token\n\nRead\n[Platform Token documentation](https://docs.dynatrace.com/docs/shortlink/platform-tokens)\nfor more details.\n\n```yaml\ndynatrace:\n  environments:\n    - name: xxxxxxxx\n      url: https://xxxxxxxx.apps.dynatrace.com\n      platformToken: \u003cplatformToken\u003e\n```\n\n\u003e See below how to configure\n\u003e [multiple Dynatrace environments](#multi-environment-support).\n\n### Run Backstage with Dynatrace Plugins\n\nTo start the app, run:\n\n```sh\nyarn install\nyarn dev\n```\n\nBackstage is pre-configured but relies on appropriate data to be available in\nthe demo Dynatrace environment. See [catalog-info.yaml](./catalog-info.yaml) for\ndetails.\n\n## Additional Features\n\nFind here additional features to customize the plugin for different\nrequirements.\n\n### DQL Query logs\n\nSetup `LOG_QUERY=true` node env variable to be able to log DQL queries during\nexecution\n\n### Multi-environment Support\n\nIf the component in Backstage should display data from multiple Dynatrace\nenvironments, add each Dynatrace environment to the `dynatrace.environments`\nlist in the `app-config.local.yaml` file.\n\n```yaml\ndynatrace:\n  environments:\n    - name: xxxxxxxx\n      url: https://xxxxxxxx.apps.dynatrace.com\n      tokenUrl: https://sso.dynatrace.com/sso/oauth2/token\n      accountUrn: \u003caccountUrn\u003e\n      clientId: \u003cclientId\u003e\n      clientSecret: \u003cclientSecret\u003e\n    - name: yyyyyyyy\n      url: https://yyyyyyyy.apps.dynatrace.com\n      tokenUrl: https://sso.dynatrace.com/sso/oauth2/token\n      accountUrn: \u003caccountUrn\u003e\n      clientId: \u003cclientId\u003e\n      clientSecret: \u003cclientSecret\u003e\n```\n\n### Kubernetes Use Case\n\nUsing the `EntityKubernetesDeploymentsCard`, you can see the Kubernetes\ndeployments in your Dynatrace environment.\n\n```jsx\n\u003cEntityKubernetesDeploymentsCard\n  title=\"Show me my Kubernetes deployments\"\n  queryId=\"dynatrace.kubernetes-deployments\"\n/\u003e\n```\n\n_Convention:_ Kubernetes pods will be listed for the corresponding Backstage\ncomponent if they are properly annotated in the deployment descriptor. See\n[annotations](https://backstage.io/docs/features/software-catalog/descriptor-format/#annotations-optional).\n\n\u003e [!NOTE] Please ensure you have the `storage:entities:read` permission to read\n\u003e Kubernetes deployments.\n\nExample:\n\n```yaml\nbackstage.io/kubernetes-id: \u003cbackstage-namespace\u003e.\u003cbackstage-component-name\u003e *)\nbackstage.io/kubernetes-namespace: namespace\nbackstage.io/kubernetes-label-selector: stage=hardening,name=frontend\n```\n\n\\*) While any value can be defined, it is recommended to set the backstage\nnamespace followed by the component name.\n\n- The annotation `backstage.io/kubernetes-id` will look for the Kubernetes label\n  `backstage.io/kubernetes-id`.\n- The annotation `backstage.io/kubernetes-namespace` will look for the\n  Kubernetes namespace.\n- The annotation `backstage.io/kubernetes-label-selector` will look for the\n  labels defined in it. So\n  `backstage.io/kubernetes-label-selector: stage=hardening,name=frontend` will\n  look for a Kubernetes label `stage` with the value `hardening` and a label\n  `name` with the value `frontend`.\n\nIf a `backstage.io/kubernetes-label-selector` is given,\n`backstage.io/kubernetes-id` is ignored.\n\nIf no namespace is given, it looks for all namespaces. There is no fallback to\n`default`.\n\nThe query for fetching the monitoring data for Kubernetes deployments is defined\nhere:\n[`dynatrace.kubernetes-deployments`](plugins/dql-backend/src/service/queries.ts).\nYou can change this query for all cards or override it using a custom query.\n\n_Convention:_ To display the pod's version in Backstage, annotate it using the\nfollowing key-value pair:\n\n```yaml\napp.kubernetes.io/version: \u003cversion\u003e\n```\n\n### Site Reliability Guardian Validations\n\nUsing the `EntityDqlQueryCard` with the queryId `dynatrace.srg-validations`, you\ncan see the validations of the site reliability guardians in your Dynatrace\nenvironment.\n\n```jsx\n\u003cEntityDqlQueryCard\n  title=\"Site Reliability Guardian Validations\"\n  queryId=\"dynatrace.srg-validations\"\n/\u003e\n```\n\n\u003e [!NOTE] Please ensure you have the `storage:events:read` and\n\u003e `storage:bizevents:read` permissions to read guardian validations.\n\nTo filter for specific guardians, you can filter tags defined in the\n`metadata.annotations` property of the `catalog-info.yaml` file under the key\n`dynatrace.com/guardian-tags`.\n\n```yaml\napiVersion: backstage.io/v1alpha1\nkind: Component\nmetadata:\n  name: demo-backstage\n  description: Backstage Demo instance.\n  annotations:\n    backstage.io/kubernetes-id: kubernetescustom\n    dynatrace.com/guardian-tags: 'service=my-service,stage=development,novalue'\n```\n\nThere are two ways to filter tags:\n\n1. **Key-Value Match:** The tag must match both the key and the value. For\n   example, the key `service` must have the value `my-service`.\n2. **Key Exists:** The tag key must exist with any value. For example, the key\n   `novalue`.\n\nThe difference between these filtering methods is indicated by the presence of\nthe `=` symbol.\n\nFor the example provided above, the filtered guardian should have at least these\ntags:\n\n```yaml\nservice: my-service\nstage: development\nnovalue:\n```\n\nSet `dynatrace.com/guardian-tags` to empty, if do not want to filter for\nspecific tags.\n\n```yaml\ndynatrace.com/guardian-tags: ''\n```\n\nSee\n[How to create a Site Reliability Guardian](https://docs.dynatrace.com/docs/shortlink/guardian-create-srg#create-a-guardian-from-a-template)\nand [Guardian tags](https://docs.dynatrace.com/docs/shortlink/srg-landing#tags).\n\nThe query for fetching the monitoring data for Site Reliability Guardian\nvalidations is defined here:\n[`dynatrace.srg-validations`](plugins/dql-backend/src/service/queries.ts). You\ncan change this query for all cards or override it using a custom query.\n\n### Custom Queries\n\nYou can also register your custom queries and use them with\n`EntityDqlQueryCard`:\n\n```yaml\ndynatrace:\n  queries:\n    - id: my-custom-query\n      query: \u003e\n        fetch events | filter event.kind == \"DAVIS_EVENT\" | fields event.kind,\n        timestamp\n```\n\n\u003e [!NOTE] Depending on your custom query ensure you have the\n\u003e [relevant permissions](https://docs.dynatrace.com/docs/platform/grail/organize-data/assign-permissions-in-grail#grail-permissions-table).\n\nQueries can contain placeholders, which will be replaced with the values from\nthe context in which it is executed. These placeholders are prefixed with `$$`\nin order to escape the\n[environment variable substitution](https://backstage.io/docs/conf/writing/#environment-variable-substitution)\nof Backstage. The following placeholders are available:\n\n- `$${componentNamespace}` the namespace of the Backstage component, as defined\n  in the Backstage catalog\n- `$${componentName}` the name of the Backstage component, as defined in the\n  Backstage catalog\n- `$${environmentName}` the name of the environment (e.g. `production`), as\n  defined in the Dynatrace environment configuration\n- `$${environmentUrl}` the URL of the environment (e.g.\n  `https://my-environment.dynatrace.com`), as defined in the Dynatrace\n  environment configuration\n\nFor example, to filter for the events of the component, you could use the\nfollowing in your query:\n\n```dql\nfilter backstageComponent == \"$${componentNamespace}.$${componentName}\"\n```\n\nTo be able to render correctly, the DQL must return an array. Links are also\nsupported and can be added to the table if transformed like this:\n\n`Logs: { type: 'link', title: 'Link to Logs', url: 'https...' }`\n\nAn example of a valid DQL result would be:\n\n```json\n[\n  {\n    \"Name\": \"backstage\",\n    \"Namespace\": \"hardening\",\n    \"LogCount\": 0,\n    \"latestLog\": null,\n    \"hasLogs\": false,\n    \"Link\": {\n      \"type\": \"link\",\n      \"text\": \"Click me\",\n      \"url\": \"https://backstage.io\"\n    },\n    \"metadata\": {\n      \"time\": {\n        \"timestamp\": \"xyz\"\n      }\n    }\n  }\n]\n```\n\nTo include the result table for your custom query, you would reference the query\nby its ID with the `custom.` prefix:\n\n```jsx\n\u003cEntityDqlQueryCard\n  title=\"My Custom Query Results\"\n  queryId=\"custom.my-custom-query\"\n/\u003e\n```\n\n### Custom Queries within the catalog-info.yaml file of the Backstage Entity\n\nYou can register custom queries in the `metadata.dynatrace.queries` property of\na component within the `catalog-info.yaml` file\n\n```yaml\napiVersion: backstage.io/v1alpha1\nkind: Component\nmetadata:\n  name: demo-backstage\n  description: Backstage Demo instance.\n  annotations:\n    backstage.io/kubernetes-id: kubernetescustom\n    dynatrace.com/guardian-tags: 'service=my-service,stage=development,novalue'\n  dynatrace:\n    queries:\n      - id: Error Logs\n        description: Fetch Error Logs\n        query: \u003e\n          fetch logs, from: -2d\n                | filter status == \"ERROR\"\n                | sort timestamp desc\n                | fieldsAdd content=if(isNull(content), \"N/A\", else: content)\n                | fieldsAdd source=if(isNull(log.source), \"N/A\", else:\n          log.source)\n                | fieldsAdd host=if(isNull(host.name), \"N/A\", else: host.name)\n                | fieldsAdd environment = \"${environmentName}\"\n                | fieldsKeep timestamp, source, content, host, environment\nspec:\n  type: website\n  owner: user:default/mjakl\n  lifecycle: experimental\n  system: integrations\n```\n\nAs mentioned before, queries can contain placeholders. In the catalog-info.yaml\nfile, the placeholders are prefixed with a single `$`. Please find the supported\nplaceholders listed\n[here](https://github.com/Dynatrace/backstage-plugin/blob/eac6adfe0c25fc7a4e5b0b7d05d5dc83464f3652/README.md#custom-queries).\n\nTo include the result tables for the custom queries of the entity, you would\nuse:\n\n```jsx\n\u003cEntityCatalogInfoQueryCard /\u003e\n```\n\nThis component displays a result table for each query. The order in which the\ntables are displayed depends on the order of the entity's queries defined in the\ncatalog-info.yaml file.\n\n### Optional environment limitation for custom queries\n\nIt is possible to specify the environments in which each query defined in the\n`app-config.yaml` and `catalog-info.yaml` is executed.\n\nBy default, queries are executed against all defined environments.\n\nExample query defined in `catalog-info.yaml` with environment limitation:\n\n```yaml\napiVersion: backstage.io/v1alpha1\nkind: Component\nmetadata:\n  name: demo-backstage\n  description: Backstage Demo instance.\n  annotations:\n    backstage.io/kubernetes-id: kubernetescustom\n    dynatrace.com/guardian-tags: 'service=my-service,stage=development,novalue'\n  dynatrace:\n    queries:\n      - id: Error Logs\n        description: Fetch Error Logs\n        environments:\n          - tenant1\n          - tenant2\n        query: \u003e\n          fetch logs, from: -2d\n                | filter status == \"ERROR\"\n                | sort timestamp desc\n                | fieldsAdd content=if(isNull(content), \"N/A\", else: content)\n                | fieldsAdd source=if(isNull(log.source), \"N/A\", else: log.source)\n                | fieldsAdd host=if(isNull(host.name), \"N/A\", else: host.name)\n                | fieldsAdd environment = \"${environmentName}\"\n                | fieldsKeep timestamp, source, content, host, environment\n```\n\nThe environments defined for a query must align with the environments names\nconfigured in the `app-config.local.yaml` file.\n\n### Multiline DQL queries with comments\n\nTo use comments within your custom DQL queries, use literal block style YAML\nstyle, indicated by a pipe (`|`). See\n[YAML Spec | Literal Style](https://yaml.org/spec/1.2.2/#literal-style).\n\n```yaml\nquery: |\n  fetch logs\n    // Filter for errors\n    | filter loglevel == \"ERROR\"\n    /*\n     *  Count them\n     */\n    | summarize sum=count() // Assign column label\n```\n\n### Sample DQL Queries\n\nThese are sample custom queries for the `app-config.yaml`. To use these queries\nin the `catalog-info.yaml`, you need to remove one `$` from the placeholders.\n\nQuery Error Logs:\n\n```\nfetch logs, from: -2d\n        | filter status == \"ERROR\"\n        | sort timestamp desc\n        | fieldsAdd content=if(isNull(content), \"N/A\", else: content)\n        | fieldsAdd source=if(isNull(log.source), \"N/A\", else: log.source)\n        | fieldsAdd host=if(isNull(host.name), \"N/A\", else: host.name)\n        | fieldsAdd environment = \"$${environmentName}\"\n        | fieldsKeep timestamp, source, content, host, environment\n```\n\nQuery Problem Events:\n\n```\nfetch events, from: -2d\n        | filter event.kind==\"DAVIS_PROBLEM\"\n        | fieldsAdd category=if(isNull(event.category), \"N/A\", else: event.category)\n        | fieldsAdd id=if(isNull(event.id), \"N/A\", else: event.id)\n        | fieldsAdd status=if(isNull(event.status), \"N/A\", else: event.status)\n        | fieldsAdd name=if(isNull(event.name), \"N/A\", else: event.name)\n        | fieldsAdd environment = \"$${environmentName}\"\n        | fieldsKeep timestamp, category, id, name, status, environment\n```\n\nQuery Security Vulnerabilities:\n\n```\nfetch security.events, from: -2d\n        | filter event.provider==\"Dynatrace\"\n        | filter event.kind==\"SECURITY_EVENT\"\n        | filter event.type==\"VULNERABILITY_STATUS_CHANGE_EVENT\"\n        | filter event.level==\"VULNERABILITY\"\n        | fieldsAdd environment = \"$${environmentName}\"\n        | fieldsKeep timestamp, event.status, vulnerability.display_id, event.id, vulnerability.title, vulnerability.risk.level, vulnerability.display_id, environment\n```\n\n### Backlink to Dynatrace\n\nTo link from a table cell to a Dynatrace app, the DQL query must contain a\nrecord with the proper `type`, `text`, and `url`. This is an example to link to\nthe Dynatrace Kubernetes app filtered by Kubernetes pods:\n\n```\nfetch dt.entity.cloud_application, from: -10m\n| fieldsAdd Workload = record({type=\"link\", text=entity.name, url=concat(\"\\${environmentUrl}/ui/apps/dynatrace.kubernetes/resources/pod?entityId=\", id)})\n```\n\nThe query returns a result of:\n\n```json\n[\n  {\n    \"Workload\": {\n      \"type\": \"link\",\n      \"text\": \"\u003cENTITY_NAME\u003e\",\n      \"url\": \"https://\u003cENVIRONMENT_URL\u003e/ui/apps/dynatrace.kubernetes/resources/pod?entityId=\u003cENTITY_ID\u003e\"\n    }\n  }\n]\n```\n\n## E2E Testing\n\nThis repository includes end-to-end tests using Playwright to verify the plugin\nfunctionality.\n\n### Prerequisites\n\nTo run e2e tests locally, you need:\n\n1. **Dynatrace Environment** with the following:\n\n   - A Dynatrace tenant with API and App URLs\n   - One authentication method for query execution:\n     - A\n       [**Platform Token**](https://docs.dynatrace.com/docs/manage/identity-access-management/access-tokens-and-oauth-clients/platform-tokens#my-platform-tokens)\n       with scopes:\n       - `storage:buckets:read`\n       - `storage:events:read`\n     - Or an **OAuth client** with equivalent read scopes for DQL and storage\n       access\n\n2. **Environment Variables** set in your terminal (only the variables for your\n   chosen auth method are required):\n\n   **Platform Token auth:**\n\n   ```bash\n   export TENANT_APP_URL=\"https://{your-environment-id}.apps.dynatrace.com\"\n   export PLATFORM_TOKEN=\"\u003cyour-platform-token\u003e\"\n   ```\n\n   **OAuth auth:**\n\n   ```bash\n   export TENANT_APP_URL=\"https://{your-environment-id}.apps.dynatrace.com\"\n   export OAUTH_CLIENT_ID=\"\u003cyour-oauth-client-id\u003e\"\n   export OAUTH_CLIENT_SECRET=\"\u003cyour-oauth-client-secret\u003e\"\n   export OAUTH_ACCOUNT_URN=\"\u003cyour-oauth-account-urn\u003e\"\n   export OAUTH_TOKEN_URL=\"https://sso.dynatrace.com/sso/oauth2/token\"\n   ```\n\n### Running E2E Tests Locally\n\n1. **Install Playwright browsers** (first time only):\n\n```bash\nyarn e2e:install-browsers\n```\n\n2. **Run with Platform Token auth**:\n\n```bash\nyarn e2e:platform-token\n```\n\n3. **Run with OAuth auth**:\n\n```bash\nyarn e2e:oauth\n```\n\n4. Optional manual breakdown (both auth modes use the same flow):\n\n```bash\n# Generate config\nyarn e2e:config:platform-token\n# or\nyarn e2e:config:oauth\n\n# Type-check and execute tests\nyarn tsc:e2e\nyarn e2e\n```\n\nThe templates use a deterministic `data record(...)` query with a fixed `testId`\nso no extra data ingestion is required.\n\nOr run in UI mode for debugging:\n\n```bash\nyarn e2e:ui\n```\n\n### What the E2E Tests Verify\n\nThe e2e tests validate:\n\n- ✅ Configuration is read correctly from `app-config.local.yaml`\n- ✅ Backstage development server starts successfully\n- ✅ Authentication via Dynatrace Platform Token works\n- ✅ Authentication via Dynatrace OAuth client credentials works\n- ✅ Custom DQL queries execute and populate data tables with expected results\n- ✅ Fixed test data from the query template is rendered in the UI\n\n### Continuous Integration\n\nE2E tests run automatically in GitHub Actions on every push and pull request to\nthe `main` branch. The CI workflow:\n\n- Runs e2e as a dedicated reusable workflow that can also be started directly\n  via workflow dispatch\n- Executes two sequential passes: `platform-token` first, then `oauth`\n- Generates temporary `app-config.local.yaml` from auth-mode-specific templates\n  for each pass\n- Runs Playwright tests (Chromium)\n- Uploads auth-mode-specific Playwright reports as artifacts\n\n**Note:** E2E tests are skipped on forked pull requests to protect repository\nsecrets.\n\n## Help \u0026 Support\n\nThis Backstage integration is an open source project. The features are fully\nsupported by [Dynatrace](https://www.dynatrace.com).\n\n**Get help:**\n\n- Ask a question in the\n  [product forums](https://community.dynatrace.com/t5/Using-Dynatrace/ct-p/UsingDynatrace)\n\n**Open a GitHub issue to:**\n\n- Report minor defects, minor items, or typos\n- Ask for improvements or changes\n- Ask any questions related to the community effort\n- Contribute as per our [Contribution guidelines](#contributing)\n\nSLAs don't apply for GitHub tickets.\n\n**Customers can open a ticket on the\n[Dynatrace support portal](https://support.dynatrace.com/supportportal/) to:**\n\n- Get support from the Dynatrace technical support engineering team\n- Manage and resolve product related technical issues\n\nSLAs apply according to the customer's support level.\n\n## Contributing\n\nEveryone is welcome to contribute to this repository. See our\n[contributing guidelines](./CONTRIBUTING.md), raise\n[issues](https://github.com/Dynatrace/backstage-plugin/issues) or submit\n[pull requests](https://github.com/Dynatrace/backstage-plugin/pulls).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynatrace%2Fbackstage-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdynatrace%2Fbackstage-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynatrace%2Fbackstage-plugin/lists"}