top of page

Dynatrace Custom Apps

Updated: Nov 5, 2024

Dynatrace is great for creating simple and not so simple dashboards and notebooks. The use-case we describe can be solved by a standard dashboard but let’s use this use-case anyway to explore custom apps in Dynatrace.


Our Use-case


Our imaginary setup consists of two systems – a booking system and a processing layer. The booking system takes orders saves them to a DB (which we don’t have access to) and logs them into a log with a transaction ID. The processing layer picks up the order and processes it via various transformations. It also logs the intermediate states but only the first log entry has the transaction ID and session ID, the subsequent log entries only have a newly created session ID. So the first log looks like this:

From the above we want to filter on the highlighted trd_id and use to it to extract the session_id which we’ll use to extract the logs produced by the processing layer.

Next, we’ll use a DQL to match on the session_id…


fetch logs
| parse content, """DATA 'trx_id:'LD:trx_id', session_id:'LD:session_id"""
| parse content, """DATA 'session_id:'LD:session_idx','"""
| filter isNotNull(trx_id) or isNotNull(session_idx)
| filter matchesValue(session_id,"465654-65454-5458") or matchesValue(session_idx,"465654-65454-5458")
| sort timestamp
| fieldsAdd session_id = if(isNull(session_id),session_idx, else: session_id)
| fields trx_id, session_id, content

… to produce the final output:

As final result, we want something like the below – a form with the ability to enter a transaction ID and find all log entries associated with it from both the booking system and the processing layer:


I’ve had a lot of experience with Dynatrace over the last few years, creating dashboards, notebooks, custom extension (SQL, snmp and Python) so it wasn’t all that difficult to get started on the Dynatrace side of things with the DQLs etc. However, for custom apps you need a few molre resources:


The solution


Here is the code of the page with commentary:


import React from 'react';
import { useState } from 'react';
import { Flex } from '@dynatrace/strato-components/layouts';
import { Heading, Text } from '@dynatrace/strato-components/typography';
import { TitleBar } from '@dynatrace/strato-components-preview/layouts';
import { convertToColumns } from '@dynatrace/strato-components-preview/conversion-utilities';
import { DataTable, TableColumn, TableRow } from '@dynatrace/strato-components-preview/tables';
import { ProgressCircle } from '@dynatrace/strato-components/content';
import { useDqlQuery } from '@dynatrace-sdk/react-hooks';
import { Controller, useForm } from 'react-hook-form';
import { logTrxQuery, logSessionQuery } from '../queries';
// The queries mentioned above are captured in the queries.ts file and are parameterised to take trx_id and session_id as inputs

import { FormField, Label, TextInput } from '@dynatrace/strato-components-preview/forms';
import { Button } from '@dynatrace/strato-components/buttons';

function ResultsTable({ trxid }) {
  // The below defines the output table and how it ties to the recordset
  const columns: TableColumn[] = [
    {
      header: 'Transaction ID',
      accessor: 'trx_id',
      autoWidth: true,
    },
    {
      header: 'Session ID',
      accessor: 'session_id',
      autoWidth: true,
    },
    {
      header: 'Content',
      accessor: 'content',
      autoWidth: true,
    },
  ];  
  // Below we define the first query to be executed
  const result = useDqlQuery({
    body: {
      query: logTrxQuery(trxid), 
    },
  },
  );

  // Extract session_id from the result
  let session_id;
  if (!result.isLoading) {
	  result?.data?.records.forEach((value, key) => {
		session_id = value?.session_id?.toString() ?? ""
	  })
  }

  // Run the second query supplying the session ID
  const resultSess = useDqlQuery({
    body: {
      query: logSessionQuery(session_id),
    },
  },
  );
  if (resultSess.isLoading) {return (<ProgressCircle />)}
  else  {
	  return (
		<DataTable data={resultSess?.data?.records || []} columns={columns}>
		   <DataTable.Pagination />
        </DataTable>
	  );
  }
}

// This is where it all comes together
export const LogMesh = () => {
  const [trxid, setTrxid] = useState("");
  const [sent, setSent] = useState(false);
  const handleChange = (event) => {
	setTrxid(event)
	setSent(false)
  };
  function handleClick(e) {
    setSent(true);
  }
  return (
    <Flex width="100%" flexDirection="column" justifyContent="center" gap={16}>
      <TitleBar>
        <TitleBar.Title>Log meshing</TitleBar.Title>
      </TitleBar>
	  <FormField>
	  <Label>Enter Transaction ID</Label>
      <TextInput type="text" id="trxid" name="trxid" value={trxid} onChange={handleChange}/> 
	  <Button onClick={handleClick} variant="emphasized">Search</Button>
	  {sent && <ResultsTable trxid={trxid}/>}
     </FormField>
    </Flex>
  );
};

If you'd like the full code or any help with your custom app, let us know here. Thanks for reading.

 
 
 

Comments


> TEST

> PERFORMANCE

©2024 testperformance.co.uk. Registered in England No 06317427.

Registered office: 10A High St, Chislehurst BR7 5AN. 

testperformance.co.uk is a trading style of Marri Jann Ltd

Subscribe to Our Newsletter

Thanks for submitting!

Follow Us On:

  • LinkedIn
bottom of page