Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan
- [#107](https://github.com/kobsio/kobs/pull/107): Add new option for Prometheus chart legend and change formatting of values.
- [#108](https://github.com/kobsio/kobs/pull/108): Improve tooltip position in all nivo charts.
- [#121](https://github.com/kobsio/kobs/pull/121): :warning: *Breaking change:* :warning: Allow multiple queries in the panel options for the Elasticsearch plugin.
- [#130](https://github.com/kobsio/kobs/pull/130): :warning: *Breaking change:* :warning: Allow multiple queries in the panel options for the Jaeger plugin.

## [v0.5.0](https://github.com/kobsio/kobs/releases/tag/v0.5.0) (2021-08-03)

Expand Down
4 changes: 3 additions & 1 deletion deploy/demo/istio-system/jaeger-application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ spec:
plugin:
name: elasticsearch
options:
query: "kubernetes.namespace: istio-system AND kubernetes.labels.app: jaeger"
queries:
- name: All Jaeger Logs
query: "kubernetes.namespace: istio-system AND kubernetes.labels.app: jaeger"
4 changes: 3 additions & 1 deletion deploy/demo/kobs/base/dashboards/traces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ spec:
plugin:
name: jaeger
options:
service: "{{ .service }}"
showChart: true
queries:
- name: "{{ .service }}"
service: "{{ .service }}"
18 changes: 15 additions & 3 deletions docs/plugins/jaeger.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,22 @@ The following options can be used for a panel with the Jaeger plugin:

| Field | Type | Description | Required |
| ----- | ---- | ----------- | -------- |
| showChart | boolean | If this is `true` the chart with the traces will be shown. | No |
| queries | [[]Query](#query) | A list of Jaeger queries, which can be selected by the user. | Yes |

### Query

| Field | Type | Description | Required |
| ----- | ---- | ----------- | -------- |
| name | string | A name for the Jaeger query, which is displayed in the select box. | Yes |
| limit | string | The maximum number of traces which should be shown. The default value is `20`. | No |
| maxDuration | string | The maximum duration for the retrieved traces (e.g. `1s`). | No |
| minDuration | string | The minimum duration for the retrieved traces (e.g. `100ms`). | No |
| service | string | The service to retrieve traces for. | Yes |
| operation | string | An optional operation to retrieve traces for. | No |
| tags | string | Tags, which the traces must be contain. | No |
| showChart | boolean | If this is `true` the chart with the traces will be shown. | No |

For example the following dashboard shows all traces for the specified service (e.g. `reviews.bookinfo`).
For example the following dashboard shows all requests and all slow requests from Jaeger for the specified service (e.g. `reviews.bookinfo`).

```yaml
---
Expand All @@ -40,6 +47,11 @@ spec:
plugin:
name: jaeger
options:
service: "{{ .service }}"
showChart: true
queries:
- name: "{{ .service }} requests"
service: "{{ .service }}"
- name: "{{ .service }} slow requests"
service: "{{ .service }}"
minDuration: 1000ms
```
8 changes: 4 additions & 4 deletions plugins/clickhouse/src/components/panel/LogsActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export const Actions: React.FunctionComponent<IActionsProps> = ({ name, queries,
isOpen={show}
isPlain={true}
position="right"
dropdownItems={queries.map((query) => [
dropdownItems={queries.map((query, index) => (
<DropdownItem
key={0}
key={index}
component={
<Link
to={`/${name}?time=${times.time}&timeEnd=${times.timeEnd}&timeStart=${times.timeStart}&query=${
Expand All @@ -33,8 +33,8 @@ export const Actions: React.FunctionComponent<IActionsProps> = ({ name, queries,
{query.name}
</Link>
}
/>,
])}
/>
))}
/>
</CardActions>
);
Expand Down
6 changes: 3 additions & 3 deletions plugins/clickhouse/src/components/panel/SQLActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ export const Actions: React.FunctionComponent<IActionsProps> = ({ name, queries
isOpen={show}
isPlain={true}
position="right"
dropdownItems={queries.map((query) => [
<DropdownItem key={0} component={<Link to={`/${name}?query=${query.query}`}>{query.name}</Link>} />,
])}
dropdownItems={queries.map((query, index) => (
<DropdownItem key={index} component={<Link to={`/${name}?query=${query.query}`}>{query.name}</Link>} />
))}
/>
</CardActions>
);
Expand Down
8 changes: 4 additions & 4 deletions plugins/elasticsearch/src/components/panel/LogsActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export const Actions: React.FunctionComponent<IActionsProps> = ({ name, queries,
isOpen={show}
isPlain={true}
position="right"
dropdownItems={queries.map((query) => [
dropdownItems={queries.map((query, index) => (
<DropdownItem
key={0}
key={index}
component={
<Link
to={`/${name}?time=${times.time}&timeEnd=${times.timeEnd}&timeStart=${times.timeStart}&query=${
Expand All @@ -33,8 +33,8 @@ export const Actions: React.FunctionComponent<IActionsProps> = ({ name, queries,
{query.name}
</Link>
}
/>,
])}
/>
))}
/>
</CardActions>
);
Expand Down
17 changes: 11 additions & 6 deletions plugins/jaeger/src/components/page/Traces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,18 @@ const Traces: React.FunctionComponent<ITracesProps> = ({ name, displayName, desc
name={name}
title=""
showDetails={setSelectedTrace}
queries={[
{
limit: options.limit,
maxDuration: options.maxDuration,
minDuration: options.minDuration,
name: '',
operation: options.operation,
service: options.service,
tags: options.tags,
},
]}
showChart={true}
limit={options.limit}
maxDuration={options.maxDuration}
minDuration={options.minDuration}
operation={options.operation}
service={options.service}
tags={options.tags}
times={options.times}
/>
) : null}
Expand Down
9 changes: 2 additions & 7 deletions plugins/jaeger/src/components/panel/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const Panel: React.FunctionComponent<IPanelProps> = ({
options,
showDetails,
}: IPanelProps) => {
if (!options || !options.service || !times) {
if (!options || !options.queries || !Array.isArray(options.queries) || options.queries.length === 0 || !times) {
return (
<PluginOptionsMissing
title={title}
Expand All @@ -34,12 +34,7 @@ export const Panel: React.FunctionComponent<IPanelProps> = ({
description={description}
showDetails={showDetails}
showChart={options.showChart || false}
limit={options.limit || '20'}
maxDuration={options.maxDuration || ''}
minDuration={options.minDuration || ''}
operation={options.operation || ''}
service={options.service}
tags={options.tags || ''}
queries={options.queries}
times={times}
/>
);
Expand Down
158 changes: 98 additions & 60 deletions plugins/jaeger/src/components/panel/Traces.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,56 @@
import { Alert, AlertActionLink, AlertVariant, Spinner } from '@patternfly/react-core';
import {
Alert,
AlertActionLink,
AlertVariant,
Select,
SelectOption,
SelectOptionObject,
SelectVariant,
Spinner,
} from '@patternfly/react-core';
import { QueryObserverResult, useQuery } from 'react-query';
import React from 'react';
import React, { useState } from 'react';

import { IOptions, ITrace } from '../../utils/interfaces';
import { IPluginTimes, PluginCard } from '@kobsio/plugin-core';
import { IQuery, ITrace } from '../../utils/interfaces';
import { encodeTags, transformTraceData } from '../../utils/helpers';
import { PluginCard } from '@kobsio/plugin-core';
import TracesActions from './TracesActions';
import TracesChart from './TracesChart';
import TracesList from './TracesList';
import { addColorForProcesses } from '../../utils/colors';

interface ITracesProps extends IOptions {
interface ITracesProps {
name: string;
title: string;
description?: string;
showDetails?: (details: React.ReactNode) => void;
showChart: boolean;
queries: IQuery[];
times: IPluginTimes;
showDetails?: (details: React.ReactNode) => void;
}

const Traces: React.FunctionComponent<ITracesProps> = ({
name,
title,
description,
times,
showDetails,
showChart,
limit,
maxDuration,
minDuration,
operation,
service,
tags,
times,
queries,
}: ITracesProps) => {
const [showSelect, setShowSelect] = useState<boolean>(false);
const [selectedQuery, setSelectedQuery] = useState<IQuery>(queries[0]);

const { isError, isLoading, error, data, refetch } = useQuery<ITrace[], Error>(
['jaeger/traces', name, limit, maxDuration, minDuration, operation, service, tags, times],
['jaeger/traces', name, selectedQuery, times],
async () => {
try {
const response = await fetch(
`/api/plugins/jaeger/traces/${name}?limit=${limit}&maxDuration=${maxDuration}&minDuration=${minDuration}&operation=${operation}&service=${service}&tags=${encodeTags(
tags,
)}&timeStart=${times.timeStart}&timeEnd=${times.timeEnd}`,
`/api/plugins/jaeger/traces/${name}?limit=${selectedQuery.limit || '20'}&maxDuration=${
selectedQuery.maxDuration || ''
}&minDuration=${selectedQuery.minDuration || ''}&operation=${selectedQuery.operation || ''}&service=${
selectedQuery.service || ''
}&tags=${encodeTags(selectedQuery.tags || '')}&timeStart=${times.timeStart}&timeEnd=${times.timeEnd}`,
{
method: 'get',
},
Expand Down Expand Up @@ -71,56 +82,83 @@ const Traces: React.FunctionComponent<ITracesProps> = ({
},
);

const select = (
event: React.MouseEvent<Element, MouseEvent> | React.ChangeEvent<Element>,
value: string | SelectOptionObject,
): void => {
const query = queries.filter((query) => query.name === value);
if (query.length === 1) {
setSelectedQuery(query[0]);
}
setShowSelect(false);
};

return (
<PluginCard
title={title}
description={description}
transparent={true}
actions={
<TracesActions
name={name}
limit={limit}
maxDuration={maxDuration}
minDuration={minDuration}
operation={operation}
service={service}
tags={tags}
times={times}
/>
}
actions={<TracesActions name={name} queries={queries} times={times} />}
>
{isLoading ? (
<div className="pf-u-text-align-center">
<Spinner />
</div>
) : isError ? (
<Alert
variant={AlertVariant.danger}
title="Could not get traces"
actionLinks={
<React.Fragment>
<AlertActionLink onClick={(): Promise<QueryObserverResult<ITrace[], Error>> => refetch()}>
Retry
</AlertActionLink>
</React.Fragment>
}
>
<p>{error?.message}</p>
</Alert>
) : data && data.length > 0 ? (
<React.Fragment>
{showChart ? (
<React.Fragment>
<TracesChart name={name} traces={data} showDetails={showDetails} />
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</React.Fragment>
) : null}
<div>
{queries.length > 1 ? (
<div>
<Select
variant={SelectVariant.single}
typeAheadAriaLabel="Select query"
placeholderText="Select query"
onToggle={(): void => setShowSelect(!showSelect)}
onSelect={select}
selections={selectedQuery.name}
isOpen={showSelect}
>
{queries.map((query, index) => (
<SelectOption
key={index}
value={query.name}
description={`Service: ${query.service || '-'}, Operation: ${query.operation || '-'}, Max Duration: ${
query.maxDuration || '-'
}, Min Duration: ${query.minDuration || '-'}, Tags: ${query.tags || '-'}`}
/>
))}
</Select>
<p>&nbsp;</p>
</div>
) : null}

{isLoading ? (
<div className="pf-u-text-align-center">
<Spinner />
</div>
) : isError ? (
<Alert
variant={AlertVariant.danger}
title="Could not get traces"
actionLinks={
<React.Fragment>
<AlertActionLink onClick={(): Promise<QueryObserverResult<ITrace[], Error>> => refetch()}>
Retry
</AlertActionLink>
</React.Fragment>
}
>
<p>{error?.message}</p>
</Alert>
) : data && data.length > 0 ? (
<React.Fragment>
{showChart ? (
<React.Fragment>
<TracesChart name={name} traces={data} showDetails={showDetails} />
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</React.Fragment>
) : null}

<TracesList name={name} traces={data} showDetails={showDetails} />
</React.Fragment>
) : null}
<TracesList name={name} traces={data} showDetails={showDetails} />
</React.Fragment>
) : null}
</div>
</PluginCard>
);
};
Expand Down
Loading