Skip to main content

Dynatrace

Port's Dynatrace integration allows you to import problem, slo and entity resources from your Dynatrace instance into Port, according to your mapping and definition.

Common use cases

  • Map your monitored entities, problems and SLOs in Dynatrace.
  • Watch for object changes (create/update) in real-time, and automatically apply the changes to your entities in Port.

Installation

Choose one of the following installation methods:

Using this installation option means that the integration will be hosted by Port, with a customizable resync interval to ingest data into Port.

Beta feature

The Hosted by Port option is currently in beta, and is still undergoing final testing before its official release.

Should you encounter any bugs or functionality issues, please let us know so we can rectify them as soon as possible.
Your help is greatly appreciated! ⭐

Live event support

Currently, live events are not supported for integrations hosted by Port.
Resyncs will be performed periodically every 1 hour by default (can be configured differently after installation), or manually triggered by you via Port's UI.

Therefore, real-time events (including GitOps) will not be ingested into Port immediately.
Support for live events is WIP and will be supported in the near future.

Installation

To install, follow the following steps:

  1. Go to the Data sources page of your portal.

  2. Click on the + Data source button in the top-right corner.

  3. Click on the relevant integration in the list.

  4. Under Select your installation method, choose Hosted by Port.

  5. Configure the integration settings and application settings as you wish (see below for details).

Application settings

Every integration hosted by Port has the following customizable application settings, which are configurable after installation:

  • Resync interval: The frequency at which Port will ingest data from the integration. There are various options available, ranging from every 1 hour to once a day.

  • Send raw data examples: A boolean toggle (enabled by default). If enabled, raw data examples will be sent from the integration to Port. These examples are used when testing your mapping configuration, they allow you to run your jq expressions against real data and see the results.

Integration settings

Every integration has its own tool-specific settings, under the Integration settings section.
Each of these settings has an ⓘ icon next to it, which you can hover over to see a description of the setting.

Port secrets

Some integration settings require sensitive pieces of data, such as tokens.
For these settings, Port secrets will be used, ensuring that your sensitive data is encrypted and secure.

When changing such a setting, you will be prompted to choose an existing secret or create a new one:



Port source IP addresses

When using this installation method, Port will make outbound calls to your 3rd-party applications from static IP addresses.
You may need to add these addresses to your allowlist, in order to allow Port to interact with the integrated service:

54.73.167.226  
63.33.143.237
54.76.185.219

Generating Dynatrace API key

  1. Navigate to <instanceURL>/ui/apps/dynatrace.classic.tokens/ui/access-tokens. For example, if you access your Dynatrace instance at https://npm82883.apps.dynatrace.com, you should navigate to https://npm82883.apps.dynatrace.com/ui/apps/dynatrace.classic.tokens/ui/access-tokens.
  2. Click Generate new token to create a new token. Ensure the permissions: DataExport, Read entities, Read problems and Read SLO are assigned to the token. The DataExport permission allows Dynatrace to perform healthchecks before ingestion starts.

Constructing Dynatrace Host URL

Your Dynatrace host URL should be https://<environment-id>.live.dynatrace.com. Note that there is a difference between the instance URL and the API host URL. The former contains apps while the latter (as shown prior) uses live. This means if your environment ID is npm82883, your API host URL should be https://npm82883.live.dynatrace.com.

Ingesting Dynatrace objects

The Dynatrace integration uses a YAML configuration to describe the process of loading data into the developer portal.

Here is an example snippet from the config which demonstrates the process for getting entity data from Dynatrace:

createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: entity
selector:
query: "true"
port:
entity:
mappings:
identifier: .entityId
title: .displayName
blueprint: '"dynatraceEntity"'
properties:
firstSeen: ".firstSeenTms / 1000 | todate"
lastSeen: ".lastSeenTms / 1000 | todate"
type: .type
tags: .tags[].stringRepresentation

The integration makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from Dynatrace's API events.

Configuration structure

The integration configuration determines which resources will be queried from Dynatrace, and which entities and properties will be created in Port.

Supported resources

The following resources can be used to map data from Dynatrace, it is possible to reference any field that appears in the API responses linked below for the mapping configuration.

  • The root key of the integration configuration is the resources key:

    resources:
    - kind: entity
    selector:
    ...
  • The kind key is a specifier for an Dynatrace object:

      resources:
    - kind: entity
    selector:
    ...
  • The selector and the query keys allow you to filter which objects of the specified kind will be ingested into your software catalog:

    resources:
    - kind: entity
    selector:
    query: "true" # JQ boolean expression. If evaluated to false - this object will be skipped.
    entityTypes: ["APPLICATION", "SERVICE"] # An optional list of entity types to filter by. If not specified, defaults to ["APPLICATION", "SERVICE"].
    port:
  • The port, entity and the mappings keys are used to map the Dynatrace object fields to Port entities. To create multiple mappings of the same kind, you can add another item in the resources array:

    resources:
    - kind: entity
    selector:
    query: "true"
    entityTypes: ["APPLICATION", "SERVICE"]
    port:
    entity:
    mappings: # Mappings between one Dynatrace object to a Port entity. Each value is a JQ query.
    identifier: .entityId
    title: .displayName
    blueprint: '"dynatraceEntity"'
    properties:
    firstSeen: ".firstSeenTms / 1000 | todate"
    lastSeen: ".lastSeenTms / 1000 | todate"
    type: .type
    tags: .tags[].stringRepresentation
    managementZones: .managementZones[].name
    properties: .properties
    fromRelationships: .fromRelationships
    toRelationships: .toRelationships
    - kind: entity # In this instance entity is mapped again with a different filter
    selector:
    query: '.displayName == "MyEntityName"'
    entityTypes: ["APPLICATION", "SERVICE"]
    port:
    entity:
    mappings: ...
    Blueprint key

    Note the value of the blueprint key - if you want to use a hardcoded string, you need to encapsulate it in 2 sets of quotes, for example use a pair of single-quotes (') and then another pair of double-quotes (")

Configuring real-time updates

Currently, the Dynatrace API lacks support for programmatic webhook creation. To set up a webhook configuration in Dynatrace for sending alert notifications to the Ocean integration, follow these steps:

Prerequisite

Prepare a webhook URL using this format: {app_host}/integration/webhook/problem. The app_host parameter should match the ingress or external load balancer where the integration will be deployed. For example, if your ingress or load balancer exposes the Dynatrace Ocean integration at https://myservice.domain.com, your webhook URL should be https://myservice.domain.com/integration/webhook/problem.

Create a webhook in Dynatrace

  1. Go to Dynatrace.
  2. Go to Settings > Integration > Problem notifications.
  3. Select Add notification.
  4. Select Custom integration from the available notification types.
  5. Configure the notification using the following details.
    1. Enabled - ensure the notification is enabled.
    2. Display name - use a meaningful name such as Port Ocean Webhook.
    3. Webhook URL - enter the value of the URL you created above.
    4. Enable Call webhook is new events merge into existing problems.
    5. Custom payload - paste the following configuration:
    {
    "State":"{State}",
    "ProblemID":"{ProblemID}",
    "ProblemTitle":"{ProblemTitle}"
    }
    You can customize to your taste, the only important thing is the ProblemID key. The webhook integration will not work without it. 6. Alerting profile - select the corresponding alerting profile. 7. Leave the rest of the fields as is.
  6. Click Save changes.

Ingest data into Port

To ingest Dynatrace objects using the integration configuration, you can follow the steps below:

  1. Go to the DevPortal Builder page.
  2. Select a blueprint you want to ingest using Dynatrace.
  3. Choose the Ingest Data option from the menu.
  4. Select Dynatrace under the Incident Management category.
  5. Modify the configuration according to your needs.
  6. Click Resync.

Examples

Examples of blueprints and the relevant integration configurations:

Entity

Entity blueprint
{
"identifier": "dynatraceEntity",
"description": "This blueprint represents a Dynatrace Entity",
"title": "Dynatrace Entity",
"icon": "Dynatrace",
"schema": {
"properties": {
"firstSeen": {
"type": "string",
"title": "First Seen",
"description": "The timestamp at which the entity was first seen, in UTC milliseconds.",
"format": "date-time"
},
"lastSeen": {
"type": "string",
"title": "Last Seen",
"description": "The timestamp at which the entity was last seen, in UTC milliseconds.",
"format": "date-time"
},
"type": {
"type": "string",
"title": "Type",
"description": "The type of the entity."
},
"tags": {
"type": "array",
"title": "Tags",
"description": "A list of tags of the entity.",
"items": {
"type": "string"
}
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Integration configuration
createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: entity
selector:
query: "true"
entityTypes: ["APPLICATION", "SERVICE"] # An optional list of entity types to filter by. If not specified, defaults to ["APPLICATION", "SERVICE"].
port:
entity:
mappings:
identifier: .entityId
title: .displayName
blueprint: '"dynatraceEntity"'
properties:
firstSeen: ".firstSeenTms / 1000 | todate"
lastSeen: ".lastSeenTms / 1000 | todate"
type: .type
tags: .tags[].stringRepresentation

Problem

Problem blueprint
{
"identifier": "dynatraceProblem",
"description": "This blueprint represents a Dynatrace Problem",
"title": "Dynatrace Problem",
"icon": "Dynatrace",
"schema": {
"properties": {
"entityTags": {
"type": "array",
"title": "Entity Tags",
"description": "A list of all entity tags of the problem.",
"items": {
"type": "string"
}
},
"evidenceDetails": {
"type": "array",
"title": "Evidence Details",
"description": "A list of all evidence details of the problem.",
"items": {
"type": "string"
}
},
"managementZones": {
"type": "array",
"title": "Management Zones",
"description": "A list of all management zones that the problem belongs to.",
"items": {
"type": "string"
}
},
"problemFilters": {
"type": "array",
"title": "Problem Filters",
"description": "A list of alerting profiles that match the problem.",
"items": {
"type": "string"
}
},
"severityLevel": {
"type": "string",
"title": "Severity Level",
"description": "The severity level of the problem.",
"enum": [
"AVAILABILITY",
"CUSTOM_ALERT",
"ERROR",
"INFO",
"MONITORING_UNAVAILABLE",
"PERFORMANCE",
"RESOURCE_CONTENTION"
],
"enumColors": {
"AVAILABILITY": "blue",
"CUSTOM_ALERT": "turquoise",
"ERROR": "red",
"INFO": "green",
"MONITORING_UNAVAILABLE": "darkGray",
"PERFORMANCE": "orange",
"RESOURCE_CONTENTION": "yellow"
}
},
"status": {
"type": "string",
"title": "Status",
"description": "The status of the problem.",
"enum": ["CLOSED", "OPEN"],
"enumColors": {
"CLOSED": "green",
"OPEN": "red"
}
},
"startTime": {
"type": "string",
"title": "Start Time",
"description": "The start time of the problem, in UTC milliseconds.",
"format": "date-time"
},
"endTime": {
"type": "string",
"title": "End Time",
"description": "The end time of the problem, in UTC milliseconds.",
"format": "date-time"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"impactedEntities": {
"title": "Impacted Entities",
"target": "dynatraceEntity",
"required": false,
"many": true
},
"linkedProblemInfo": {
"title": "Linked Problem Info",
"target": "dynatraceProblem",
"required": false,
"many": false
},
"rootCauseEntity": {
"title": "Root Cause Entity",
"target": "dynatraceEntity",
"required": false,
"many": false
}
}
}
Integration configuration
createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: problem
selector:
query: "true"
port:
entity:
mappings:
identifier: .problemId
title: .title
blueprint: '"dynatraceProblem"'
properties:
entityTags: .entityTags[].stringRepresentation
evidenceDetails: .evidenceDetails.details[].displayName
managementZones: .managementZones[].name
problemFilters: .problemFilters[].name
severityLevel: .severityLevel
status: .status
startTime: ".startTime / 1000 | todate"
endTime: ".endTime | if . == -1 then null else (./1000 | todate) end"
relations:
impactedEntities: .impactedEntities[].entityId.id
linkedProblemInfo: .linkedProblemInfo.problemId
rootCauseEntity: .rootCauseEntity.entityId.id

SLO

SLO blueprint
{
"identifier": "dynatraceSlo",
"description": "This blueprint represents a Dynatrace SLO",
"title": "Dynatrace SLO",
"icon": "Dynatrace",
"schema": {
"properties": {
"status": {
"type": "string",
"title": "Status",
"description": "The status of the SLO.",
"enum": ["FAILURE", "WARNING", "SUCCESS"],
"enumColors": {
"FAILURE": "red",
"WARNING": "yellow",
"SUCCESS": "green"
}
},
"target": {
"type": "number",
"title": "Target",
"description": "The target value of the SLO."
},
"enabled": {
"type": "boolean",
"title": "Enabled",
"description": "Whether the SLO is enabled."
},
"warning": {
"type": "number",
"title": "Warning",
"description": "The warning value of the SLO. At warning state the SLO is still fulfilled but is getting close to failure."
},
"error": {
"type": "string",
"title": "Error",
"description": "The error of the SLO calculation. If the value differs from NONE, there is something wrong with the SLO calculation."
},
"errorBudget": {
"type": "number",
"title": "Error Budget",
"description": "The error budget of the calculated SLO."
},
"evaluatedPercentage": {
"type": "number",
"title": "Evaluated Percentage",
"description": "The calculated status value of the SLO."
},
"evaluationType": {
"type": "string",
"title": "Evaluation Type",
"description": "The type of the SLO evaluation."
},
"filter": {
"type": "string",
"title": "Filter",
"description": "The filter for the SLO evaluation."
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Integration configuration
createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: slo
selector:
query: "true"
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"dynatraceSlo"'
properties:
status: .status
target: .target
enabled: .enabled
warning: .warning
error: .error
errorBudget: .errorBudget
evaluatedPercentage: .evaluatedPercentage
evaluationType: .evaluationType
filter: .filter

Let's Test It

This section includes a sample response data from Dynatrace. In addition, it includes the entity created from the resync event based on the Ocean configuration provided in the previous section.

Payload

Here is an example of the payload structure from Dynatrace:

Entity response data
{
"displayName": "my host",
"entityId": "HOST-06F288EE2A930951",
"firstSeenTms": 1574697667547,
"fromRelationships": {
"isInstanceOf": [
{
"id": "HOST_GROUP-0E489369D663A4BF",
"type": "HOST_GROUP"
}
]
},
"icon": {
"customIconPath": "host",
"primaryIconType": "linux",
"secondaryIconType": "microsoft-azure-signet"
},
"lastSeenTms": 1588242361417,
"managementZones": [
{
"id": "6239538939987181652",
"name": "main app"
}
],
"properties": {
"bitness": 64,
"cpuCores": 8,
"monitoringMode": "FULL_STACK",
"networkZoneId": "aws.us.east01",
"osArchitecture": "X86",
"osType": "LINUX"
},
"tags": [
{
"context": "CONTEXTLESS",
"key": "architecture",
"stringRepresentation": "architecture:x86",
"value": "x86"
},
{
"context": "ENVIRONMENT",
"key": "Infrastructure",
"stringRepresentation": "[ENVIRONMENT]Infrastructure:Linux",
"value": "Linux"
}
],
"toRelationships": {
"isDiskOf": [
{
"id": "DISK-0393340DCA3853B0",
"type": "DISK"
}
]
},
"type": "HOST"
}
Problem response data
{
"affectedEntities": [
{
"entityId": {
"id": "string",
"type": "string"
},
"name": "string"
}
],
"displayId": "string",
"endTime": 1574697669865,
"entityTags": [
{
"context": "CONTEXTLESS",
"key": "architecture",
"stringRepresentation": "architecture:x86",
"value": "x86"
},
{
"context": "ENVIRONMENT",
"key": "Infrastructure",
"stringRepresentation": "[ENVIRONMENT]Infrastructure:Linux",
"value": "Linux"
}
],
"evidenceDetails": {
"details": [
{
"displayName": "Availability evidence",
"entity": {},
"evidenceType": "AVAILABILITY_EVIDENCE",
"groupingEntity": {},
"rootCauseRelevant": true,
"startTime": 1
},
{
"displayName": "User action evidence",
"entity": {},
"evidenceType": "USER_ACTION_EVIDENCE",
"groupingEntity": {},
"rootCauseRelevant": true,
"startTime": 1
}
],
"totalCount": 1
},
"impactAnalysis": {
"impacts": [
{
"estimatedAffectedUsers": 1,
"impactType": "APPLICATION",
"impactedEntity": {}
}
]
},
"impactLevel": "APPLICATION",
"impactedEntities": [{}],
"linkedProblemInfo": {
"displayId": "string",
"problemId": "string"
},
"managementZones": [
{
"id": "string",
"name": "HOST"
}
],
"problemFilters": [
{
"id": "E2A930951",
"name": "BASELINE"
}
],
"problemId": "06F288EE2A930951",
"recentComments": {
"comments": [
{
"authorName": "string",
"content": "string",
"context": "string",
"createdAtTimestamp": 1,
"id": "string"
}
],
"nextPageKey": "AQAAABQBAAAABQ==",
"pageSize": 1,
"totalCount": 1
},
"rootCauseEntity": {},
"severityLevel": "AVAILABILITY",
"startTime": 1574697667547,
"status": "CLOSED",
"title": "title"
}
SLO response data
{
"burnRateMetricKey": "func:slo.errorBudgetBurnRate.payment_service_availability",
"denominatorValue": 90,
"description": "Rate of successful payments per week",
"enabled": true,
"error": "NONE",
"errorBudget": 1.25,
"errorBudgetBurnRate": {
"burnRateType": "SLOW",
"burnRateValue": 1.25,
"burnRateVisualizationEnabled": true,
"estimatedTimeToConsumeErrorBudget": 24,
"fastBurnThreshold": 1.5,
"sloValue": 95
},
"errorBudgetMetricKey": "func:slo.errorBudget.payment_service_availability",
"evaluatedPercentage": 96.25,
"evaluationType": "AGGREGATE",
"filter": "type(\"SERVICE\")",
"id": "123e4567-e89b-42d3-a456-556642440000",
"metricDenominator": "builtin:service.requestCount.server",
"metricExpression": "(100)*(builtin:service.errors.server.successCount:splitBy())/(builtin:service.requestCount.server:splitBy())",
"metricKey": "func:slo.payment_service_availability",
"metricNumerator": "builtin:service.errors.server.successCount",
"metricRate": "builtin:service.successes.server.rate",
"name": "Payment service availability",
"normalizedErrorBudgetMetricKey": "func:slo.normalizedErrorBudget.payment_service_availability",
"numeratorValue": 80,
"problemFilters": "[type(\"SERVICE\")]",
"relatedOpenProblems": 1,
"relatedTotalProblems": 1,
"status": "WARNING",
"target": 95,
"timeframe": "-1d",
"useRateMetric": true,
"warning": 97.5
}

Mapping Result

The combination of the sample payload and the Ocean configuration generates the following Port entity:

Entity entity in Port
{
"identifier": "HOST-06F288EE2A930951",
"title": "my host",
"blueprint": "dynatraceEntity",
"team": [],
"icon": "Dynatrace",
"properties": {
"firstSeen": "2019-11-25T14:14:27Z",
"lastSeen": "2020-04-30T14:52:41Z",
"type": "HOST",
"tags": ["architecture:x86", "[ENVIRONMENT]Infrastructure:Linux"]
},
"relations": {},
"createdAt": "2024-2-6T09:30:57.924Z",
"createdBy": "hBx3VFZjqgLPEoQLp7POx5XaoB0cgsxW",
"updatedAt": "2024-2-6T11:49:20.881Z",
"updatedBy": "hBx3VFZjqgLPEoQLp7POx5XaoB0cgsxW"
}
Problem entity in Port
{
"identifier": "06F288EE2A930951",
"title": "title",
"blueprint": "dynatraceProblem",
"team": [],
"icon": "Dynatrace",
"properties": {
"entityTags": ["architecture:x86", "[ENVIRONMENT]Infrastructure:Linux"],
"evidenceDetails": ["Availability evidence", "User action evidence"],
"managementZones": ["HOST"],
"problemFilters": ["BASELINE"],
"severityLevel": "AVAILABILITY",
"status": "CLOSED",
"startTime": "2019-11-25T14:14:27Z",
"endTime": "2020-04-30T14:52:41Z"
},
"relations": {
"impactedEntities": ["HOST-06F288EE2A930951"],
"linkedProblemInfo": "06F288EE2A930951",
"rootCauseEntity": "HOST-06F288EE2A930951"
},
"createdAt": "2024-2-6T09:30:57.924Z",
"createdBy": "hBx3VFZjqgLPEoQLp7POx5XaoB0cgsxW",
"updatedAt": "2024-2-6T11:49:20.881Z",
"updatedBy": "hBx3VFZjqgLPEoQLp7POx5XaoB0cgsxW"
}
SLO entity in Port
{
"identifier": "123e4567-e89b-42d3-a456-556642440000",
"title": "Payment service availability",
"blueprint": "dynatraceSlo",
"team": [],
"icon": "Dynatrace",
"properties": {
"status": "WARNING",
"target": 95,
"enabled": true,
"warning": 97.5,
"error": "NONE",
"errorBudget": 1.25,
"evaluatedPercentage": 96.25,
"evaluationType": "AGGREGATE",
"filter": "type(\"SERVICE\")"
},
}

Alternative installation via webhook

While the Ocean integration described above is the recommended installation method, you may prefer to use a webhook to ingest problem from Dynatrace. If so, use the following instructions:

Note that when using this method, data will be ingested into Port only when the webhook is triggered.

Webhook installation (click to expand)

Port configuration

Create the following blueprint definitions:

Dynatrace microservice blueprint
{
"identifier": "microservice",
"title": "Microservice",
"icon": "Service",
"schema": {
"properties": {
"description": {
"title": "Description",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Dynatrace problem blueprint
{
"identifier": "dynatraceProblem",
"description": "This blueprint represents a Dynatrace problem in our software catalog",
"title": "Dynatrace Problem",
"icon": "Deployment",
"schema": {
"properties": {
"state": {
"type": "string",
"title": "Problem State"
},
"url": {
"type": "string",
"format": "url",
"title": "Problem URL"
},
"details": {
"type": "string",
"title": "Details"
},
"impact": {
"type": "string",
"title": "Problem Impact"
},
"severity": {
"type": "string",
"title": "Problem Severity"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"title": "Tags"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"microservice": {
"title": "Impacted Services",
"target": "microservice",
"required": false,
"many": true
}
}
}

Create the following webhook configuration using Port's UI:

Dynatrace problem webhook configuration
  1. Basic details tab - fill the following details:

    1. Title : Dynatrace Problem Mapper;
    2. Identifier : dynatrace_problem_mapper;
    3. Description : A webhook configuration for problem events from Dynatrace;
    4. Icon : Dynatrace;
  2. Integration configuration tab - fill the following JQ mapping:

    [
    {
    "blueprint": "dynatraceProblem",
    "entity": {
    "identifier": ".body.PID | tostring",
    "title": ".body.ProblemTitle",
    "properties": {
    "state": ".body.State",
    "url": ".body.ProblemURL",
    "details": ".body.ProblemDetailsText",
    "impact": ".body.ProblemImpact",
    "severity": ".body.ProblemSeverity",
    "tags": ".body.ProblemTags | split(\", \")"
    },
    "relations": {
    "microservice": "[.body.ImpactedEntities[].entity]"
    }
    }
    }
    ]
  3. Click Save at the bottom of the page.

note

The webhook configuration's relation mapping will function properly only when the identifiers of the Port microservice entities match the names of the entities in your Dynatrace.

If there is a mismatch, you can utilize Dynatrace Tags to align the actual identifier in Port.

To do this, create a tag with the key proj and value microservice_identifier.

Then, update the relation JQ syntax to establish a connection between the Dynatrace problem and the Port microservice. Here is the updated JQ Mappings:

{
"blueprint": "dynatraceProblem",
"entity": {
...Properties mappings,
"relations": {
"microservice": ".body.ProblemTags | split(\", \") | map(select(test(\"proj:\")) | sub(\"proj:\";\"\"))"
}
}
}
Details

JQ expression explained The above JQ expression will split the tags by comma and space, then filter the tags that start with proj: and remove the proj: prefix from the tag value.

Create a webhook in Dynatrace

  1. Log in to Dynatrace with your credentials.
  2. Click on Settings at the left sidebar of the page.
  3. Choose Integration and click on Problem notifications.
  4. Select Add notification.
  5. Select Custom integration from the available integration types.
  6. Input the following details:
    1. Display name - use a meaningful name such as Port Webhook.

    2. Webhook URL - enter the value of the url key you received after creating the webhook configuration.

    3. Overview - you can add an optional HTTP header to your webhook request.

    4. Custom payload - When a problem is detected or resolved on your entity, this payload will be sent to the webhook URL. You can enter this JSON placeholder in the textbox:

      {
      "State":"{State}",
      "PID":"{PID}",
      "ProblemTitle":"{ProblemTitle}",
      "ImpactedEntity": "{ImpactedEntity}",
      "ProblemDetailsText": "{ProblemDetailsText}",
      "ProblemImpact": "{ProblemImpact}",
      "ProblemSeverity": "{ProblemSeverity}",
      "ProblemURL": "{ProblemURL}",
      "ProblemTags": "{ProblemTags}",
      "ImpactedEntities": {ImpactedEntities}
      }
    5. Alerting profile - configure your preferred alerting rule or use the default one.

  7. Click Save changes at the bottom of the page.
tip

To view the different payloads and events available in Dynatrace webhooks, look here.

Done! Any problem detected on your Dynatrace entity will trigger a webhook event. Port will parse the events according to the mapping and update the catalog entities accordingly.

Let's Test It

This section includes a sample response data from Dynatrace. In addition, it includes the entity created from the resync event based on the Ocean configuration provided in the previous section.

Payload

Here is an example of the payload structure from Dynatrace:

Problem response data
{
"affectedEntities": [
{
"entityId": {
"id": "string",
"type": "string"
},
"name": "string"
}
],
"displayId": "string",
"endTime": 1574697669865,
"entityTags": [
{
"context": "CONTEXTLESS",
"key": "architecture",
"stringRepresentation": "architecture:x86",
"value": "x86"
},
{
"context": "ENVIRONMENT",
"key": "Infrastructure",
"stringRepresentation": "[ENVIRONMENT]Infrastructure:Linux",
"value": "Linux"
}
],
"evidenceDetails": {
"details": [
{
"displayName": "Availability evidence",
"entity": {},
"evidenceType": "AVAILABILITY_EVIDENCE",
"groupingEntity": {},
"rootCauseRelevant": true,
"startTime": 1
},
{
"displayName": "User action evidence",
"entity": {},
"evidenceType": "USER_ACTION_EVIDENCE",
"groupingEntity": {},
"rootCauseRelevant": true,
"startTime": 1
}
],
"totalCount": 1
},
"impactAnalysis": {
"impacts": [
{
"estimatedAffectedUsers": 1,
"impactType": "APPLICATION",
"impactedEntity": {}
}
]
},
"impactLevel": "APPLICATION",
"impactedEntities": [{}],
"linkedProblemInfo": {
"displayId": "string",
"problemId": "string"
},
"managementZones": [
{
"id": "string",
"name": "HOST"
}
],
"problemFilters": [
{
"id": "E2A930951",
"name": "BASELINE"
}
],
"problemId": "06F288EE2A930951",
"recentComments": {
"comments": [
{
"authorName": "string",
"content": "string",
"context": "string",
"createdAtTimestamp": 1,
"id": "string"
}
],
"nextPageKey": "AQAAABQBAAAABQ==",
"pageSize": 1,
"totalCount": 1
},
"rootCauseEntity": {},
"severityLevel": "AVAILABILITY",
"startTime": 1574697667547,
"status": "CLOSED",
"title": "title"
}

Mapping Result

The combination of the sample payload and the Ocean configuration generates the following Port entity:

Problem entity in Port
{
"identifier": "06F288EE2A930951",
"title": "title",
"blueprint": "dynatraceProblem",
"team": [],
"icon": "Dynatrace",
"properties": {
"entityTags": ["architecture:x86", "[ENVIRONMENT]Infrastructure:Linux"],
"evidenceDetails": ["Availability evidence", "User action evidence"],
"managementZones": ["HOST"],
"problemFilters": ["BASELINE"],
"severityLevel": "AVAILABILITY",
"status": "CLOSED",
"startTime": "2019-11-25T14:14:27Z",
"endTime": "2020-04-30T14:52:41Z"
},
"relations": {
"impactedEntities": ["HOST-06F288EE2A930951"],
"linkedProblemInfo": "06F288EE2A930951",
"rootCauseEntity": "HOST-06F288EE2A930951"
},
"createdAt": "2024-2-6T09:30:57.924Z",
"createdBy": "hBx3VFZjqgLPEoQLp7POx5XaoB0cgsxW",
"updatedAt": "2024-2-6T11:49:20.881Z",
"updatedBy": "hBx3VFZjqgLPEoQLp7POx5XaoB0cgsxW"

}

Ingest Dynatrace Entities

In this example, you will create a dynatrace_entity blueprint that ingests monitored entities from your Dynatrace account. You will then add a Python script to make API calls to Dynatrace REST API and fetch data for your account.