Commit ae09ccbf by Andrej Ocenas Committed by GitHub

Trace UI demo (#20297)

* Add integration with Jeager
Add Jaeger datasource and modify derived fields in loki to allow for opening a trace in Jager in separate split.
Modifies build so that this branch docker images are pushed to docker hub
Add a traceui dir with docker-compose and provision files for demoing.:wq

* Enable docker logger plugin to send logs to loki

* Add placeholder zipkin datasource

* Fixed rebase issues, added enhanceDataFrame to non-legacy code path

* Trace selector for jaeger query field

* Fix logs default mode for Loki

* Fix loading jaeger query field services on split

* Updated grafana image in traceui/compose file

* Fix prettier error

* Hide behind feature flag, clean up unused code.

* Fix tests

* Fix tests

* Cleanup code and review feedback

* Remove traceui directory

* Remove circle build changes

* Fix feature toggles object

* Fix merge issues

* Fix some null errors

* Fix test after strict null changes

* Review feedback fixes

* Fix toggle name

Co-authored-by: David Kaltschmidt <david.kaltschmidt@gmail.com>
parent b6f73e35
......@@ -26,7 +26,11 @@ export namespace dateMath {
* @param roundUp See parseDateMath function.
* @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used.
*/
export function parse(text: string | DateTime | Date, roundUp?: boolean, timezone?: TimeZone): DateTime | undefined {
export function parse(
text?: string | DateTime | Date | null,
roundUp?: boolean,
timezone?: TimeZone
): DateTime | undefined {
if (!text) {
return undefined;
}
......
......@@ -27,6 +27,9 @@ export interface DataLink {
// 1: If exists, handle click directly
// Not saved in JSON/DTO
onClick?: (event: DataLinkClickEvent) => void;
// At the moment this is used for derived fields for metadata about internal linking.
meta?: any;
}
export type LinkTarget = '_blank' | '_self';
......
......@@ -115,6 +115,7 @@ export interface DataSourcePluginMeta<T extends KeyValue = {}> extends PluginMet
logs?: boolean;
annotations?: boolean;
alerting?: boolean;
tracing?: boolean;
mixed?: boolean;
hasQueryHelp?: boolean;
category?: string;
......@@ -316,6 +317,7 @@ export enum DataSourceStatus {
export enum ExploreMode {
Logs = 'Logs',
Metrics = 'Metrics',
Tracing = 'Tracing',
}
export interface ExploreQueryFieldProps<
......
......@@ -19,6 +19,7 @@ interface FeatureToggles {
newEdit: boolean;
meta: boolean;
newVariables: boolean;
tracingIntegration: boolean;
}
interface LicenseInfo {
......@@ -71,6 +72,7 @@ export class GrafanaBootConfig {
newEdit: false,
meta: false,
newVariables: false,
tracingIntegration: false,
};
licenseInfo: LicenseInfo = {} as LicenseInfo;
phantomJSRenderer = false;
......
......@@ -24,7 +24,7 @@ import { LogDetailsRow } from './LogDetailsRow';
type FieldDef = {
key: string;
value: string;
links?: string[];
links?: Array<LinkModel<Field>>;
fieldIndex?: number;
};
......@@ -99,7 +99,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
return {
key: field.name,
value: field.values.get(row.rowIndex).toString(),
links: links.map(link => link.href),
links: links,
fieldIndex: field.index,
};
})
......
import React, { PureComponent } from 'react';
import { css, cx } from 'emotion';
import { LogLabelStatsModel, GrafanaTheme } from '@grafana/data';
import { Field, LinkModel, LogLabelStatsModel, GrafanaTheme } from '@grafana/data';
import { Themeable } from '../../types/theme';
import { withTheme } from '../../themes/index';
......@@ -9,6 +9,7 @@ import { stylesFactory } from '../../themes/stylesFactory';
//Components
import { LogLabelStats } from './LogLabelStats';
import { LinkButton } from '../Button/Button';
export interface Props extends Themeable {
parsedValue: string;
......@@ -16,7 +17,7 @@ export interface Props extends Themeable {
isLabel?: boolean;
onClickFilterLabel?: (key: string, value: string) => void;
onClickFilterOutLabel?: (key: string, value: string) => void;
links?: string[];
links?: Array<LinkModel<Field>>;
getStats: () => LogLabelStatsModel[] | null;
}
......@@ -122,11 +123,27 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
{links &&
links.map(link => {
return (
<span key={link}>
&nbsp;
<a href={link} target={'_blank'}>
<i className={'fa fa-external-link'} />
</a>
<span key={link.href}>
<>
&nbsp;
<LinkButton
variant={'transparent'}
size={'sm'}
icon={cx('fa', link.onClick ? 'fa-list' : 'fa-external-link')}
href={link.href}
target={'_blank'}
onClick={
link.onClick
? event => {
if (!(event.ctrlKey || event.metaKey || event.shiftKey) && link.onClick) {
event.preventDefault();
link.onClick(event);
}
}
: undefined
}
/>
</>
</span>
);
})}
......
......@@ -92,7 +92,11 @@ func pluginScenario(desc string, t *testing.T, fn func()) {
_, err := sec.NewKey("path", "testdata/test-app")
So(err, ShouldBeNil)
pm := &PluginManager{}
pm := &PluginManager{
Cfg: &setting.Cfg{
FeatureToggles: map[string]bool{},
},
}
err = pm.Init()
So(err, ShouldBeNil)
......
......@@ -18,7 +18,11 @@ func TestPluginDashboards(t *testing.T) {
_, err := sec.NewKey("path", "testdata/test-app")
So(err, ShouldBeNil)
pm := &PluginManager{}
pm := &PluginManager{
Cfg: &setting.Cfg{
FeatureToggles: map[string]bool{},
},
}
err = pm.Init()
So(err, ShouldBeNil)
......
......@@ -23,6 +23,7 @@ type DataSourcePlugin struct {
Explore bool `json:"explore"`
Table bool `json:"tables"`
Logs bool `json:"logs"`
Tracing bool `json:"tracing"`
QueryOptions map[string]bool `json:"queryOptions,omitempty"`
BuiltIn bool `json:"builtIn,omitempty"`
Mixed bool `json:"mixed,omitempty"`
......
......@@ -42,10 +42,12 @@ type PluginScanner struct {
pluginPath string
errors []error
backendPluginManager backendplugin.Manager
cfg *setting.Cfg
}
type PluginManager struct {
BackendPluginManager backendplugin.Manager `inject:""`
Cfg *setting.Cfg `inject:""`
log log.Logger
}
......@@ -164,6 +166,7 @@ func (pm *PluginManager) scan(pluginDir string) error {
scanner := &PluginScanner{
pluginPath: pluginDir,
backendPluginManager: pm.BackendPluginManager,
cfg: pm.Cfg,
}
if err := util.Walk(pluginDir, true, true, scanner.walker); err != nil {
......@@ -213,6 +216,14 @@ func (scanner *PluginScanner) walker(currentPath string, f os.FileInfo, err erro
return nil
}
if !scanner.cfg.FeatureToggles["tracingIntegration"] {
// Do not load tracing datasources if
prefix := path.Join(setting.StaticRootPath, "app/plugins/datasource")
if strings.Contains(currentPath, path.Join(prefix, "jaeger")) || strings.Contains(currentPath, path.Join(prefix, "zipkin")) {
return nil
}
}
if f.Name() == "plugin.json" {
err := scanner.loadPluginJson(currentPath)
if err != nil {
......
......@@ -15,7 +15,11 @@ func TestPluginScans(t *testing.T) {
setting.StaticRootPath, _ = filepath.Abs("../../public/")
setting.Raw = ini.Empty()
pm := &PluginManager{}
pm := &PluginManager{
Cfg: &setting.Cfg{
FeatureToggles: map[string]bool{},
},
}
err := pm.Init()
So(err, ShouldBeNil)
......@@ -34,7 +38,11 @@ func TestPluginScans(t *testing.T) {
_, err = sec.NewKey("path", "testdata/test-app")
So(err, ShouldBeNil)
pm := &PluginManager{}
pm := &PluginManager{
Cfg: &setting.Cfg{
FeatureToggles: map[string]bool{},
},
}
err = pm.Init()
So(err, ShouldBeNil)
......
......@@ -281,6 +281,7 @@ type Cfg struct {
ApiKeyMaxSecondsToLive int64
// Use to enable new features which may still be in alpha/beta stage.
FeatureToggles map[string]bool
}
......
......@@ -66,17 +66,17 @@ export interface GetExploreUrlArguments {
datasourceSrv: DataSourceSrv;
timeSrv: TimeSrv;
}
export async function getExploreUrl(args: GetExploreUrlArguments) {
export async function getExploreUrl(args: GetExploreUrlArguments): Promise<string | undefined> {
const { panel, panelTargets, panelDatasource, datasourceSrv, timeSrv } = args;
let exploreDatasource = panelDatasource;
let exploreTargets: DataQuery[] = panelTargets;
let url: string;
let url: string | undefined;
// Mixed datasources need to choose only one datasource
if (panelDatasource.meta.id === 'mixed' && exploreTargets) {
if (panelDatasource.meta?.id === 'mixed' && exploreTargets) {
// Find first explore datasource among targets
for (const t of exploreTargets) {
const datasource = await datasourceSrv.get(t.datasource);
const datasource = await datasourceSrv.get(t.datasource || undefined);
if (datasource) {
exploreDatasource = datasource;
exploreTargets = panelTargets.filter(t => t.datasource === datasource.name);
......@@ -183,7 +183,7 @@ enum ParseUiStateIndex {
Strategy = 3,
}
export const safeParseJson = (text: string) => {
export const safeParseJson = (text?: string): any | undefined => {
if (!text) {
return;
}
......@@ -365,7 +365,7 @@ export function clearHistory(datasourceId: string) {
}
export const getQueryKeys = (queries: DataQuery[], datasourceInstance: DataSourceApi): string[] => {
const queryKeys = queries.reduce((newQueryKeys, query, index) => {
const queryKeys = queries.reduce<string[]>((newQueryKeys, query, index) => {
const primaryKey = datasourceInstance && datasourceInstance.name ? datasourceInstance.name : query.key;
return newQueryKeys.concat(`${primaryKey}-${index}`);
}, []);
......@@ -381,7 +381,7 @@ export const getTimeRange = (timeZone: TimeZone, rawRange: RawTimeRange): TimeRa
};
};
const parseRawTime = (value: any): TimeFragment => {
const parseRawTime = (value: any): TimeFragment | null => {
if (value === null) {
return null;
}
......@@ -442,7 +442,7 @@ export const getValueWithRefId = (value?: any): any => {
return undefined;
};
export const getFirstQueryErrorWithoutRefId = (errors?: DataQueryError[]) => {
export const getFirstQueryErrorWithoutRefId = (errors?: DataQueryError[]): DataQueryError | undefined => {
if (!errors) {
return undefined;
}
......@@ -530,7 +530,7 @@ export const stopQueryState = (querySubscription: Unsubscribable) => {
}
};
export function getIntervals(range: TimeRange, lowLimit: string, resolution: number): IntervalValues {
export function getIntervals(range: TimeRange, lowLimit: string, resolution?: number): IntervalValues {
if (!resolution) {
return { interval: '1s', intervalMs: 1000 };
}
......@@ -542,7 +542,7 @@ export function deduplicateLogRowsById(rows: LogRowModel[]) {
return _.uniqBy(rows, 'uid');
}
export const getFirstNonQueryRowSpecificError = (queryErrors?: DataQueryError[]) => {
export const getFirstNonQueryRowSpecificError = (queryErrors?: DataQueryError[]): DataQueryError | undefined => {
const refId = getValueWithRefId(queryErrors);
return refId ? null : getFirstQueryErrorWithoutRefId(queryErrors);
return refId ? undefined : getFirstQueryErrorWithoutRefId(queryErrors);
};
......@@ -88,7 +88,7 @@ export const parseBody = (options: BackendSrvRequest, isAppJson: boolean) => {
return isAppJson ? JSON.stringify(options.data) : new URLSearchParams(options.data);
};
function serializeParams(data: Record<string, any>): string {
export function serializeParams(data: Record<string, any>): string {
return Object.keys(data)
.map(key => {
const value = data[key];
......
import _ from 'lodash';
import { DataQuery } from '@grafana/data';
export const getNextRefIdChar = (queries: DataQuery[]): string => {
export const getNextRefIdChar = (queries: DataQuery[]): string | undefined => {
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return _.find(letters, refId => {
......
import { DataSourcePluginMeta, PluginType } from '@grafana/data';
import { DataSourcePluginCategory } from 'app/types';
import { config } from '@grafana/runtime';
export function buildCategories(plugins: DataSourcePluginMeta[]): DataSourcePluginCategory[] {
const categories: DataSourcePluginCategory[] = [
{ id: 'tsdb', title: 'Time series databases', plugins: [] },
{ id: 'logging', title: 'Logging & document databases', plugins: [] },
config.featureToggles.tracingIntegration ? { id: 'tracing', title: 'Distributed tracing', plugins: [] } : null,
{ id: 'sql', title: 'SQL', plugins: [] },
{ id: 'cloud', title: 'Cloud', plugins: [] },
{ id: 'enterprise', title: 'Enterprise plugins', plugins: [] },
{ id: 'other', title: 'Others', plugins: [] },
];
].filter(item => item);
const categoryIndex: Record<string, DataSourcePluginCategory> = {};
const pluginIndex: Record<string, DataSourcePluginMeta> = {};
......@@ -66,6 +68,7 @@ function sortPlugins(plugins: DataSourcePluginMeta[]) {
graphite: 95,
loki: 90,
mysql: 80,
jaeger: 100,
postgres: 79,
gcloud: -1,
};
......
......@@ -148,13 +148,12 @@ describe('Explore', () => {
it('should filter out a query-row-specific error when looking for non-query-row-specific errors', async () => {
const queryErrors = setupErrors(true);
const queryError = getFirstNonQueryRowSpecificError(queryErrors);
expect(queryError).toBeNull();
expect(queryError).toBeUndefined();
});
it('should not filter out a generic error when looking for non-query-row-specific errors', async () => {
const queryErrors = setupErrors();
const queryError = getFirstNonQueryRowSpecificError(queryErrors);
expect(queryError).not.toBeNull();
expect(queryError).toEqual({
message: 'Error message',
status: '400',
......
......@@ -20,33 +20,33 @@ import {
changeSize,
initializeExplore,
modifyQueries,
refreshExplore,
scanStart,
setQueries,
refreshExplore,
updateTimeRange,
toggleGraph,
addQueryRow,
updateTimeRange,
} from './state/actions';
// Types
import {
AbsoluteTimeRange,
DataQuery,
DataSourceApi,
GraphSeriesXY,
PanelData,
RawTimeRange,
TimeRange,
GraphSeriesXY,
TimeZone,
AbsoluteTimeRange,
LoadingState,
ExploreMode,
} from '@grafana/data';
import { ExploreItemState, ExploreUrlState, ExploreId, ExploreUpdateState, ExploreUIState } from 'app/types/explore';
import { ExploreId, ExploreItemState, ExploreUIState, ExploreUpdateState, ExploreUrlState } from 'app/types/explore';
import { StoreState } from 'app/types';
import {
ensureQueries,
DEFAULT_RANGE,
DEFAULT_UI_STATE,
ensureQueries,
getTimeRangeFromUrl,
getTimeRange,
lastUsedDatasourceKeyForOrgId,
......@@ -70,6 +70,18 @@ const getStyles = stylesFactory(() => {
button: css`
margin: 1em 4px 0 0;
`,
// Utility class for iframe parents so that we can show iframe content with reasonable height instead of squished
// or some random explicit height.
fullHeight: css`
label: fullHeight;
height: 100%;
`,
iframe: css`
label: iframe;
border: none;
width: 100%;
height: 100%;
`,
};
});
......@@ -328,14 +340,14 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
</button>
</div>
<ErrorContainer queryError={queryError} />
<AutoSizer onResize={this.onResize} disableHeight>
<AutoSizer className={styles.fullHeight} onResize={this.onResize} disableHeight>
{({ width }) => {
if (width === 0) {
return null;
}
return (
<main className={`m-t-2 ${styles.logsMain}`} style={{ width }}>
<main className={cx('m-t-2', styles.logsMain, styles.fullHeight)} style={{ width }}>
<ErrorBoundaryAlert>
{showStartPage && StartPage && (
<div className={'grafana-info-box grafana-info-box--max-lg'}>
......@@ -379,6 +391,18 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
onStopScanning={this.onStopScanning}
/>
)}
{mode === ExploreMode.Tracing && (
<div className={styles.fullHeight}>
{queryResponse &&
!!queryResponse.series.length &&
queryResponse.series[0].fields[0].values.get(0) && (
<iframe
className={styles.iframe}
src={queryResponse.series[0].fields[0].values.get(0)}
/>
)}
</div>
)}
</>
)}
{showRichHistory && (
......@@ -448,7 +472,7 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia
newMode = supportedModes[0];
}
} else {
newMode = [ExploreMode.Metrics, ExploreMode.Logs].includes(urlMode) ? urlMode : undefined;
newMode = [ExploreMode.Metrics, ExploreMode.Logs, ExploreMode.Tracing].includes(urlMode) ? urlMode : undefined;
}
const initialUI = ui || DEFAULT_UI_STATE;
......
......@@ -366,7 +366,7 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps
containerWidth,
} = exploreItem;
const hasLiveOption = datasourceInstance?.meta?.streaming && mode === ExploreMode.Logs;
const hasLiveOption = !!(datasourceInstance?.meta?.streaming && mode === ExploreMode.Logs);
return {
datasourceMissing,
......
......@@ -14,12 +14,13 @@ import {
TimeRange,
LogsMetaItem,
GraphSeriesXY,
Field,
} from '@grafana/data';
import { ExploreId, ExploreItemState } from 'app/types/explore';
import { StoreState } from 'app/types';
import { changeDedupStrategy, updateTimeRange } from './state/actions';
import { changeDedupStrategy, updateTimeRange, splitOpen } from './state/actions';
import { toggleLogLevelAction } from 'app/features/explore/state/actionTypes';
import { deduplicatedRowsSelector } from 'app/features/explore/state/selectors';
import { getTimeZone } from '../profile/state/selectors';
......@@ -57,6 +58,7 @@ interface LogsContainerProps {
syncedTimes: boolean;
absoluteRange: AbsoluteTimeRange;
isPaused: boolean;
splitOpen: typeof splitOpen;
}
export class LogsContainer extends PureComponent<LogsContainerProps> {
......@@ -87,6 +89,30 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
return [];
};
/**
* Get links from the filed of a dataframe that was given to as and in addition check if there is associated
* metadata with datasource in which case we will add onClick to open the link in new split window. This assumes
* that we just supply datasource name and field value and Explore split window will know how to render that
* appropriately. This is for example used for transition from log with traceId to trace datasource to show that
* trace.
* @param field
* @param rowIndex
*/
getFieldLinks = (field: Field, rowIndex: number) => {
const data = getLinksFromLogsField(field, rowIndex);
return data.map(d => {
if (d.link.meta?.datasourceName) {
return {
...d.linkModel,
onClick: () => {
this.props.splitOpen(d.link.meta.datasourceName, field.values.get(rowIndex));
},
};
}
return d.linkModel;
});
};
render() {
const {
loading,
......@@ -149,7 +175,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
scanRange={range.raw}
width={width}
getRowContext={this.getLogRowContext}
getFieldLinks={getLinksFromLogsField}
getFieldLinks={this.getFieldLinks}
/>
</Collapse>
</LogsCrossFadeTransition>
......@@ -199,6 +225,7 @@ const mapDispatchToProps = {
changeDedupStrategy,
toggleLogLevelAction,
updateTimeRange,
splitOpen,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(LogsContainer));
......@@ -46,7 +46,7 @@ export class TableContainer extends PureComponent<TableContainerProps> {
return (
<Collapse label="Table" loading={loading} collapsible isOpen={showingTable} onToggle={this.onClickTableButton}>
{hasTableResult ? (
<Table data={tableResult} width={tableWidth} height={height} onCellClick={onClickCell} />
<Table data={tableResult!} width={tableWidth} height={height} onCellClick={onClickCell} />
) : (
<MetaInfoText metaItems={[{ value: '0 series returned' }]} />
)}
......
......@@ -5,9 +5,9 @@ import { connect } from 'react-redux';
import { StoreState } from 'app/types';
import { ExploreId } from 'app/types/explore';
import Explore from './Explore';
import { CustomScrollbar, ErrorBoundaryAlert } from '@grafana/ui';
import { resetExploreAction } from './state/actionTypes';
import Explore from './Explore';
interface WrapperProps {
split: boolean;
......@@ -25,7 +25,7 @@ export class Wrapper extends Component<WrapperProps> {
return (
<div className="page-scrollbar-wrapper">
<CustomScrollbar autoHeightMin={'100%'} autoHeightMax={''} className="custom-scrollbar--page">
<div className="explore-wrapper">
<div style={{ height: '100%' }} className="explore-wrapper">
<ErrorBoundaryAlert style="page">
<Explore exploreId={ExploreId.left} />
</ErrorBoundaryAlert>
......
......@@ -123,7 +123,7 @@ export function addQueryRow(exploreId: ExploreId, index: number): ThunkResult<vo
*/
export function changeDatasource(exploreId: ExploreId, datasource: string): ThunkResult<void> {
return async (dispatch, getState) => {
let newDataSourceInstance: DataSourceApi = null;
let newDataSourceInstance: DataSourceApi;
if (!datasource) {
newDataSourceInstance = await getDatasourceSrv().get();
......@@ -317,7 +317,7 @@ export const loadDatasourceReady = (
instance: DataSourceApi,
orgId: number
): PayloadAction<LoadDatasourceReadyPayload> => {
const historyKey = `grafana.explore.history.${instance.meta.id}`;
const historyKey = `grafana.explore.history.${instance.meta?.id}`;
const history = store.getObject(historyKey, []);
// Save last-used datasource
......@@ -340,7 +340,7 @@ export const loadDatasourceReady = (
export const importQueries = (
exploreId: ExploreId,
queries: DataQuery[],
sourceDataSource: DataSourceApi,
sourceDataSource: DataSourceApi | undefined,
targetDataSource: DataSourceApi
): ThunkResult<void> => {
return async dispatch => {
......@@ -352,7 +352,7 @@ export const importQueries = (
let importedQueries = queries;
// Check if queries can be imported from previously selected datasource
if (sourceDataSource.meta.id === targetDataSource.meta.id) {
if (sourceDataSource.meta?.id === targetDataSource.meta?.id) {
// Keep same queries if same type of datasource
importedQueries = [...queries];
} else if (targetDataSource.importQueries) {
......@@ -701,18 +701,31 @@ export function splitClose(itemId: ExploreId): ThunkResult<void> {
* The right state is automatically initialized.
* The copy keeps all query modifications but wipes the query results.
*/
export function splitOpen(): ThunkResult<void> {
return (dispatch, getState) => {
export function splitOpen(dataSourceName?: string, query?: string): ThunkResult<void> {
return async (dispatch, getState) => {
// Clone left state to become the right state
const leftState = getState().explore[ExploreId.left];
const queryState = getState().location.query[ExploreId.left] as string;
const urlState = parseUrlState(queryState);
const itemState: ExploreItemState = {
const leftState: ExploreItemState = getState().explore[ExploreId.left];
const rightState: ExploreItemState = {
...leftState,
queries: leftState.queries.slice(),
urlState,
};
dispatch(splitOpenAction({ itemState }));
const queryState = getState().location.query[ExploreId.left] as string;
const urlState = parseUrlState(queryState);
rightState.queries = leftState.queries.slice();
rightState.urlState = urlState;
dispatch(splitOpenAction({ itemState: rightState }));
if (dataSourceName && query) {
// This is hardcoded for Jaeger right now
const queries = [
{
query,
refId: 'A',
} as DataQuery,
];
await dispatch(changeDatasource(ExploreId.right, dataSourceName));
await dispatch(setQueriesAction({ exploreId: ExploreId.right, queries }));
}
dispatch(stateSave());
};
}
......@@ -757,7 +770,8 @@ const togglePanelActionCreator = (
}
dispatch(actionCreator({ exploreId }));
dispatch(updateExploreUIState(exploreId, uiFragmentStateUpdate));
// The switch further up is exhaustive so uiFragmentStateUpdate should definitely be initialized
dispatch(updateExploreUIState(exploreId, uiFragmentStateUpdate!));
if (shouldRunQueries) {
dispatch(runQueries(exploreId));
......
......@@ -599,6 +599,7 @@ export const updateChildRefreshState = (
const getModesForDatasource = (dataSource: DataSourceApi, currentMode: ExploreMode): [ExploreMode[], ExploreMode] => {
const supportsGraph = dataSource.meta.metrics;
const supportsLogs = dataSource.meta.logs;
const supportsTracing = dataSource.meta.tracing;
let mode = currentMode || ExploreMode.Metrics;
const supportedModes: ExploreMode[] = [];
......@@ -611,13 +612,17 @@ const getModesForDatasource = (dataSource: DataSourceApi, currentMode: ExploreMo
supportedModes.push(ExploreMode.Logs);
}
if (supportsTracing) {
supportedModes.push(ExploreMode.Tracing);
}
if (supportedModes.length === 1) {
mode = supportedModes[0];
}
// HACK: Used to set Loki's default explore mode to Logs mode.
// A better solution would be to introduce a "default" or "preferred" mode to the datasource config
if (dataSource.meta.name === 'Loki' && !currentMode) {
if (dataSource.meta.name === 'Loki' && (!currentMode || supportedModes.indexOf(currentMode) === -1)) {
mode = ExploreMode.Logs;
}
......
......@@ -54,8 +54,8 @@ describe('getLinksFromLogsField', () => {
};
const links = getLinksFromLogsField(field, 2);
expect(links.length).toBe(2);
expect(links[0].href).toBe('http://domain.com/3');
expect(links[1].href).toBe('http://anotherdomain.sk/3');
expect(links[0].linkModel.href).toBe('http://domain.com/3');
expect(links[1].linkModel.href).toBe('http://anotherdomain.sk/3');
});
it('handles zero links', () => {
......
......@@ -10,6 +10,7 @@ import {
LinkModel,
formattedValueToString,
DisplayValue,
DataLink,
} from '@grafana/data';
import { getLinkSrv } from './link_srv';
import { getFieldDisplayValuesProxy } from './fieldDisplayValuesProxy';
......@@ -143,7 +144,10 @@ export const getPanelLinksSupplier = (value: PanelModel): LinkModelSupplier<Pane
};
};
export const getLinksFromLogsField = (field: Field, rowIndex: number): Array<LinkModel<Field>> => {
export const getLinksFromLogsField = (
field: Field,
rowIndex: number
): Array<{ linkModel: LinkModel<Field>; link: DataLink }> => {
const scopedVars: any = {};
scopedVars['__value'] = {
value: {
......@@ -153,6 +157,11 @@ export const getLinksFromLogsField = (field: Field, rowIndex: number): Array<Lin
};
return field.config.links
? field.config.links.map(link => getLinkSrv().getDataLinkUIModel(link, scopedVars, field))
? field.config.links.map(link => {
return {
link,
linkModel: getLinkSrv().getDataLinkUIModel(link, scopedVars, field),
};
})
: [];
};
......@@ -13,6 +13,8 @@ const grafanaPlugin = async () =>
const influxdbPlugin = async () =>
await import(/* webpackChunkName: "influxdbPlugin" */ 'app/plugins/datasource/influxdb/module');
const lokiPlugin = async () => await import(/* webpackChunkName: "lokiPlugin" */ 'app/plugins/datasource/loki/module');
const jaegerPlugin = async () =>
await import(/* webpackChunkName: "jaegerPlugin" */ 'app/plugins/datasource/jaeger/module');
const mixedPlugin = async () =>
await import(/* webpackChunkName: "mixedPlugin" */ 'app/plugins/datasource/mixed/module');
const mysqlPlugin = async () =>
......@@ -64,6 +66,7 @@ const builtInPlugins: any = {
'app/plugins/datasource/grafana/module': grafanaPlugin,
'app/plugins/datasource/influxdb/module': influxdbPlugin,
'app/plugins/datasource/loki/module': lokiPlugin,
'app/plugins/datasource/jaeger/module': jaegerPlugin,
'app/plugins/datasource/mixed/module': mixedPlugin,
'app/plugins/datasource/mysql/module': mysqlPlugin,
'app/plugins/datasource/postgres/module': postgresPlugin,
......
import React from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { DataSourceHttpSettings } from '@grafana/ui';
export type Props = DataSourcePluginOptionsEditorProps;
export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
return (
<>
<DataSourceHttpSettings
defaultUrl={'http://localhost:16686'}
dataSourceConfig={options}
showAccessOptions={true}
onChange={onOptionsChange}
/>
</>
);
};
import React from 'react';
import { JaegerDatasource, JaegerQuery } from './datasource';
import { ButtonCascader, CascaderOption } from '@grafana/ui';
import { ExploreQueryFieldProps } from '@grafana/data';
const ALL_OPERATIONS_KEY = '__ALL__';
const NO_TRACES_KEY = '__NO_TRACES__';
type Props = ExploreQueryFieldProps<JaegerDatasource, JaegerQuery>;
interface State {
serviceOptions: CascaderOption[];
}
function getLabelFromTrace(trace: any): string {
const firstSpan = trace.spans && trace.spans[0];
if (firstSpan) {
return `${firstSpan.operationName} [${firstSpan.duration} ms]`;
}
return trace.traceID;
}
export class JaegerQueryField extends React.PureComponent<Props, State> {
constructor(props: Props, context: React.Context<any>) {
super(props, context);
this.state = {
serviceOptions: [],
};
}
componentDidMount() {
this.getServices();
}
async getServices() {
const url = '/api/services';
const { datasource } = this.props;
try {
const res = await datasource.metadataRequest(url);
if (res) {
const services = res as string[];
const serviceOptions: CascaderOption[] = services.sort().map(service => ({
label: service,
value: service,
isLeaf: false,
}));
this.setState({ serviceOptions });
}
} catch (error) {
console.error(error);
}
}
onLoadOptions = async (selectedOptions: CascaderOption[]) => {
const service = selectedOptions[0].value;
if (selectedOptions.length === 1) {
// Load operations
const operations: string[] = await this.findOperations(service);
const allOperationsOption: CascaderOption = {
label: '[ALL]',
value: ALL_OPERATIONS_KEY,
};
const operationOptions: CascaderOption[] = [
allOperationsOption,
...operations.sort().map(operation => ({
label: operation,
value: operation,
isLeaf: false,
})),
];
this.setState(state => {
const serviceOptions = state.serviceOptions.map(serviceOption => {
if (serviceOption.value === service) {
return {
...serviceOption,
children: operationOptions,
};
}
return serviceOption;
});
return { serviceOptions };
});
} else if (selectedOptions.length === 2) {
// Load traces
const operationValue = selectedOptions[1].value;
const operation = operationValue === ALL_OPERATIONS_KEY ? '' : operationValue;
const traces: any[] = await this.findTraces(service, operation);
let traceOptions: CascaderOption[] = traces.map(trace => ({
label: getLabelFromTrace(trace),
value: trace.traceID,
}));
if (traceOptions.length === 0) {
traceOptions = [
{
label: '[No traces in time range]',
value: NO_TRACES_KEY,
},
];
}
this.setState(state => {
// Place new traces into the correct service/operation sub-tree
const serviceOptions = state.serviceOptions.map(serviceOption => {
if (serviceOption.value === service) {
const operationOptions = serviceOption.children.map(operationOption => {
if (operationOption.value === operationValue) {
return {
...operationOption,
children: traceOptions,
};
}
return operationOption;
});
return {
...serviceOption,
children: operationOptions,
};
}
return serviceOption;
});
return { serviceOptions };
});
}
};
findOperations = async (service: string) => {
const { datasource } = this.props;
const url = `/api/services/${service}/operations`;
try {
return await datasource.metadataRequest(url);
} catch (error) {
console.error(error);
}
return [];
};
findTraces = async (service: string, operation?: string) => {
const { datasource } = this.props;
const { start, end } = datasource.getTimeRange();
const traceSearch = {
start,
end,
service,
operation,
limit: 10,
lookback: '1h',
maxDuration: '',
minDuration: '',
};
const url = '/api/traces';
try {
return await datasource.metadataRequest(url, traceSearch);
} catch (error) {
console.error(error);
}
return [];
};
onSelectTrace = (values: string[], selectedOptions: CascaderOption[]) => {
const { query, onChange, onRunQuery } = this.props;
if (selectedOptions.length === 3) {
const traceID = selectedOptions[2].value;
onChange({ ...query, query: traceID });
onRunQuery();
}
};
render() {
const { query, onChange } = this.props;
const { serviceOptions } = this.state;
return (
<>
<div className="gf-form-inline gf-form-inline--nowrap">
<div className="gf-form flex-shrink-0">
<ButtonCascader options={serviceOptions} onChange={this.onSelectTrace} loadData={this.onLoadOptions}>
Traces
</ButtonCascader>
</div>
<div className="gf-form gf-form--grow flex-shrink-1">
<div className={'slate-query-field__wrapper'}>
<div className="slate-query-field">
<input
style={{ width: '100%' }}
value={query.query || ''}
onChange={e =>
onChange({
...query,
query: e.currentTarget.value,
})
}
/>
</div>
</div>
</div>
</div>
</>
);
}
}
export default JaegerQueryField;
import {
dateMath,
DateTime,
MutableDataFrame,
DataSourceApi,
DataSourceInstanceSettings,
DataQueryRequest,
DataQueryResponse,
DataQuery,
} from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { DatasourceRequestOptions } from 'app/core/services/backend_srv';
import { serializeParams } from '../../../core/utils/fetch';
import { Observable, from, of } from 'rxjs';
export type JaegerQuery = {
query: string;
} & DataQuery;
export class JaegerDatasource extends DataSourceApi<JaegerQuery> {
constructor(private instanceSettings: DataSourceInstanceSettings) {
super(instanceSettings);
}
_request(apiUrl: string, data?: any, options?: DatasourceRequestOptions): Observable<Record<string, any>> {
// Hack for proxying metadata requests
const baseUrl = `/api/datasources/proxy/${this.instanceSettings.id}`;
const params = data ? serializeParams(data) : '';
const url = `${baseUrl}${apiUrl}${params.length ? `?${params}` : ''}`;
const req = {
...options,
url,
};
return from(getBackendSrv().datasourceRequest(req));
}
async metadataRequest(url: string, params?: Record<string, any>) {
const res = await this._request(url, params, { silent: true }).toPromise();
return res.data.data;
}
query(options: DataQueryRequest<JaegerQuery>): Observable<DataQueryResponse> {
//http://localhost:16686/search?end=1573338717880000&limit=20&lookback=6h&maxDuration&minDuration&service=app&start=1573317117880000
const url =
options.targets.length && options.targets[0].query
? `${this.instanceSettings.url}/trace/${options.targets[0].query}?uiEmbed=v0`
: '';
return of({
data: [
new MutableDataFrame({
fields: [
{
name: 'url',
values: [url],
},
],
}),
],
});
}
async testDatasource(): Promise<any> {
return true;
}
getTime(date: string | DateTime, roundUp: boolean) {
if (typeof date === 'string') {
date = dateMath.parse(date, roundUp);
}
return date.valueOf() * 1000;
}
getTimeRange(): { start: number; end: number } {
const range = getTimeSrv().timeRange();
return {
start: this.getTime(range.from, false),
end: this.getTime(range.to, true),
};
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg3941"
xml:space="preserve"
width="886.66669"
height="1013.3333"
viewBox="0 0 886.66669 1013.3333"
sodipodi:docname="Jaeger_Logo_Final_PANTONE REVERSE.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata3947"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs3945" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview3943"
showgrid="false"
inkscape:zoom="0.73437691"
inkscape:cx="535.56442"
inkscape:cy="530.61636"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="g3949" /><g
id="g3949"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.3333333,0,0,-1.3333333,0,1013.3333)"><g
id="g3951"
transform="matrix(0.11564109,0,0,0.11564109,-51.116401,-60.457467)"><path
d="m 2671.93,2504.33 c 32.47,-61.24 75.27,-113.74 127.39,-113.74 10.62,0 21.57,2.16 32.87,6.84 53.5,22.09 55.85,115.25 43.49,204.99 -77.04,-24.64 -144.33,-62.43 -203.75,-98.09"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3953"
inkscape:connector-curvature="0" /><path
d="m 3652.56,3440.03 c -105.48,0 -204.11,29.37 -288.16,80.37 -160.74,97.53 -268.13,274.18 -268.13,475.93 0,307.23 249.06,556.3 556.29,556.3 105.93,0 204.93,-29.63 289.21,-81.02 160.15,-97.66 267.09,-273.98 267.09,-475.28 0,-307.23 -249.07,-556.3 -556.3,-556.3 z m -74.23,-779.49 c -57.39,-24.91 -141.23,-35.96 -273.54,-37.14 0.51,-11.76 1.01,-22.53 1.59,-30.59 5.71,-75.82 -12.28,-136.77 -53.46,-181.13 -37.2,-40.13 -91.16,-62.24 -151.92,-62.24 -27.41,0 -54.47,4.49 -76.21,12.64 -23.55,8.84 -44.03,24.5 -62.67,48.6 -17.38,-49.77 -48.33,-84.2 -92.97,-102.65 -22.76,-9.39 -46.24,-14.15 -69.83,-14.15 -82.21,0 -152.5,55.71 -210.07,161.77 -7.48,-4.3 -16.33,-9.9 -23.33,-13.67 -39.59,-21.25 -87.96,-32.47 -139.86,-32.47 -97.56,0 -188.98,38.07 -244.61,101.84 -45.26,51.88 -64.87,118.96 -55.3,188.9 29.33,213.17 311.14,299.71 343.18,308.88 l 65.63,18.78 43.71,-52.44 c 5.31,-6.34 37.78,-38 157.99,-38 45.47,0 98.1,4.64 156.43,13.8 192.92,30.26 267.44,184.75 271.81,194.16 l 27.41,62.87 69.28,-0.57 c 419.03,-3.45 483.22,-187.43 492.9,-243.85 22.61,-132.29 -43.27,-245.68 -176.16,-303.34 z m -1937.94,458.92 c -160.74,97.53 -268.14,274.18 -268.14,475.93 0,307.24 249.06,556.3 556.3,556.3 105.93,0 204.93,-29.62 289.2,-81.01 160.16,-97.67 267.09,-273.98 267.09,-475.29 0,-307.23 -249.06,-556.29 -556.29,-556.29 -105.49,0 -204.11,29.36 -288.16,80.36 z m 3691.96,-918.85 c -0.17,1.08 -0.38,2.35 -0.51,3.3 -22.33,163.72 -92.16,237.16 -153.77,301.97 -57.36,60.34 -111.56,117.34 -94.11,221.99 16.13,96.74 93.09,156.26 218.85,171.75 -76.38,516.24 -188.3,1167.54 -332.18,1723.17 -71.84,277.49 -185.48,470.23 -337.88,598.37 -174.4,-89.22 -384.19,-187.3 -618.36,-288.84 -169.21,-73.37 -343.91,-145.25 -510.04,-210.56 -133.74,-143.49 -279.87,-284.91 -369.43,-325.21 -63.76,-28.69 -120.42,-40.11 -169.67,-40.11 -106.62,0 -178.6,53.48 -213.45,101.04 -40.39,-10.67 -72.66,-17.59 -94.61,-19.91 -26.25,-2.76 -64.92,-6.04 -113.3,-9.53 18.59,-48.67 11.19,-105.66 -24.46,-148.6 -39.21,-47.23 -102.39,-70.96 -191.93,-70.96 -128.84,0 -312.28,49.14 -557.55,148.21 -36.09,14.57 -69.22,27.52 -99.65,39.07 -18.78,-0.1 -37.56,-0.17 -56.33,-0.17 -0.05,0 -0.11,0 -0.17,0 -234.33,0.01 -417.46,7.37 -561.02,19.13 -157.233,-325.48 -88.905,-686.49 -31.35,-984.71 55.15,-285.79 246.5,-794.3 423.98,-1231.21 65.85,-162.09 129.76,-314.28 184.13,-441.63 480.48,-42.5 1096.51,-68.03 1768.21,-68.03 799.34,0 1519.36,36.21 2026.38,94.09 -36.94,152.03 -83.74,363.57 -91.78,417.38"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3955"
inkscape:connector-curvature="0" /><path
d="m 3260.73,3102.88 c 0,0 -93.7,-214.77 -351.38,-255.19 -67.15,-10.54 -124.22,-15.07 -172.69,-15.07 -137.51,0 -205.78,36.48 -238.51,75.7 0,0 -247.28,-70.74 -268.12,-222.35 -15.56,-113.36 96.95,-171.62 196.03,-171.62 33.45,0 65.34,6.64 90.3,20.02 98.93,53.06 247.24,169.29 445.04,194.55 17.88,2.29 42.58,3.09 71.91,3.08 67.69,0 159.94,-4.24 249.38,-4.24 101.71,0 199.81,5.5 253.92,28.97 122.31,53.06 122.31,144.02 114.54,189.49 -8.67,50.41 -83.33,154.14 -390.42,156.66"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3957"
inkscape:connector-curvature="0" /><path
d="m 3207.99,2624.15 c -23.33,0.44 -47.39,0.58 -69.64,1.14 -38.4,0.96 -74.3,1.87 -105.04,1.87 -23.55,0 -43.27,-0.4 -57.76,-2.2 22.72,-81.15 52.49,-160.81 83.19,-172.32 8.78,-3.28 24.35,-6.48 42.26,-6.48 49.7,0 117.57,24.49 108.94,139.42 -0.76,10.23 -1.37,23.86 -1.95,38.57"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3959"
inkscape:connector-curvature="0" /><path
d="M 1902.38,1168.94 C 1807.16,1147.18 1526.94,994.828 1284.81,948.57 1042.68,902.32 833.188,877.84 759.734,850.629 686.281,823.43 629.145,769.02 773.34,714.602 c 144.191,-54.411 843.38,-73.454 905.95,0 62.58,73.461 -43.15,105.296 -195.88,103.39 -108.82,-1.363 -95.47,36.559 -95.22,40.809 0,0 6.8,47.609 174.12,70.73 167.04,23.09 905.95,92.499 892.35,171.399 -13.6,78.89 -457.06,89.78 -552.28,68.01"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3961"
inkscape:connector-curvature="0" /><path
d="m 1413.91,627.941 c -78.18,-17.011 -137.54,-49.25 -132.59,-72.011 4.95,-22.75 72.35,-27.41 150.52,-10.399 78.18,17.02 137.55,49.25 132.6,72.008 -4.96,22.762 -72.35,27.41 -150.53,10.402"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3963"
inkscape:connector-curvature="0" /><path
d="m 1084.33,646.461 c -83.88,-6.672 -150.428,-30.301 -148.639,-52.77 1.789,-22.472 71.239,-35.269 155.109,-28.589 83.88,6.679 150.43,30.308 148.64,52.769 -1.79,22.469 -71.24,35.27 -155.11,28.59"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3965"
inkscape:connector-curvature="0" /><path
d="M 815.273,670.781 C 759.445,663.18 716.117,642.832 718.5,625.34 c 2.383,-17.488 49.57,-25.512 105.402,-17.91 55.828,7.609 99.157,27.949 96.774,45.449 -2.383,17.492 -49.574,25.512 -105.403,17.902"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3967"
inkscape:connector-curvature="0" /><path
d="m 617.953,695.289 c -53.906,-7.82 -95.937,-25.617 -93.887,-39.738 2.051,-14.129 47.411,-19.242 101.313,-11.41 53.902,7.82 95.934,25.621 93.883,39.738 -2.051,14.133 -47.407,19.242 -101.309,11.41"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3969"
inkscape:connector-curvature="0" /><path
d="m 580.488,699.91 c 53.903,7.82 95.938,25.621 93.887,39.75 -2.055,14.121 -47.41,19.231 -101.312,11.399 -53.903,-7.821 -95.934,-25.618 -93.887,-39.739 2.051,-14.129 47.41,-19.238 101.312,-11.41"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3971"
inkscape:connector-curvature="0" /><path
d="m 568.273,766.32 c 46.856,6.801 83.399,22.27 81.614,34.551 -1.782,12.277 -41.215,16.719 -88.071,9.918 -46.859,-6.809 -83.402,-22.277 -81.621,-34.547 1.782,-12.293 41.215,-16.73 88.078,-9.922"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3973"
inkscape:connector-curvature="0" /><path
d="m 3355.18,1092.77 c -165.96,-8.16 -541.4,10.88 -593.09,-76.18 -51.69,-87.059 152.35,-119.711 473.38,-92.5 321.03,27.211 775.37,62.57 794.41,160.52 19.05,97.94 -84.34,78.89 -95.22,141.46 -10.88,62.58 114.27,62.58 138.75,155.08 24.49,92.5 -168.68,81.62 -340.07,81.62 -171.4,0 -457.06,-16.33 -484.27,-106.11 -27.2,-89.78 130.59,-89.78 242.14,-111.54 111.54,-21.76 78.89,-62.57 78.89,-62.57 -5.44,-57.14 -48.97,-81.62 -214.92,-89.78"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3975"
inkscape:connector-curvature="0" /><path
d="m 2911.38,900.969 c -79.45,0 -143.85,-21.02 -143.85,-46.93 0,-25.918 64.4,-46.93 143.85,-46.93 79.45,0 143.85,21.012 143.85,46.93 0,25.91 -64.4,46.93 -143.85,46.93"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3977"
inkscape:connector-curvature="0" /><path
d="m 3281.72,907.09 c -52.96,0 -95.9,-19.192 -95.9,-42.848 0,-23.672 42.94,-42.851 95.9,-42.851 52.97,0 95.9,19.179 95.9,42.851 0,23.656 -42.93,42.848 -95.9,42.848"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3979"
inkscape:connector-curvature="0" /><path
d="m 3580.64,929.531 c -58.03,0 -105.08,-15.531 -105.08,-34.691 0,-19.149 47.05,-34.68 105.08,-34.68 58.04,0 105.09,15.531 105.09,34.68 0,19.16 -47.05,34.691 -105.09,34.691"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3981"
inkscape:connector-curvature="0" /><path
d="m 3811.21,970.34 c -42.25,0 -76.51,-16.438 -76.51,-36.731 0,-20.277 34.26,-36.73 76.51,-36.73 42.26,0 76.52,16.453 76.52,36.73 0,20.293 -34.26,36.731 -76.52,36.731"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3983"
inkscape:connector-curvature="0" /><path
d="m 4010.16,1011.15 c -42.83,0 -77.54,-15.99 -77.54,-35.709 0,-19.722 34.71,-35.711 77.54,-35.711 42.82,0 77.53,15.989 77.53,35.711 0,19.719 -34.71,35.709 -77.53,35.709"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3985"
inkscape:connector-curvature="0" /><path
d="m 627.063,1978.65 c 0,-46.39 101.183,-90.26 280.898,-129.29 -12.801,93.08 -4.891,186.96 7.102,260.1 -184.153,-39.42 -288,-83.82 -288,-130.81"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3987"
inkscape:connector-curvature="0" /><path
d="m 5930.11,2098.84 c -2.72,-7.53 -5.62,-14.97 -8.74,-22.28 -22.1,-51.7 -53.82,-97.35 -94.26,-135.66 -81.18,-76.89 -152.35,-122.96 -215.93,-139.76 351.23,49.36 559.72,110.84 559.72,177.51 0,42.82 -86.24,83.49 -240.79,120.19"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3989"
inkscape:connector-curvature="0" /><path
d="m 1240.47,1605.14 c 130.42,0 222.25,71 286.69,163.12 -73.75,171.04 -195.11,459.23 -310.18,762.53 -31.15,-26.5 -67.14,-66.51 -106.08,-126.87 -96.95,-150.26 -176.798,-499.88 -76.24,-684.41 41.92,-76.97 109.26,-114.37 205.81,-114.37"
style="fill:#dec795;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3991"
inkscape:connector-curvature="0" /><path
d="m 5844.76,2471.43 c -76.45,197.81 -239.03,338.23 -395.36,341.49 l -5.59,0.49 c -0.25,0.04 -30.29,4.52 -70.65,4.52 -85.15,0 -189.66,-18.18 -204.09,-104.72 -10.02,-60.05 16.25,-90.81 71.81,-149.25 63.49,-66.76 150.41,-158.2 176.46,-349.18 29.82,-218.71 83.22,-329.62 158.69,-329.64 h 0.01 c 35.24,0 99.52,21.13 205.78,121.78 130.85,123.97 118.31,321.23 62.94,464.51"
style="fill:#dec795;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3993"
inkscape:connector-curvature="0" /><path
d="m 3753.83,3810.25 c 0,-96.87 -78.53,-175.41 -175.41,-175.41 -96.87,0 -175.4,78.54 -175.4,175.41 0,96.88 78.53,175.41 175.4,175.41 96.88,0 175.41,-78.53 175.41,-175.41 z m -656.53,185.43 c 0,-201.3 106.94,-377.62 267.1,-475.28 84.05,-51 182.68,-80.37 288.16,-80.37 307.23,0 556.3,249.07 556.3,556.3 0,201.3 -106.94,377.62 -267.09,475.28 -84.05,51 -182.68,80.37 -288.17,80.37 -307.23,0 -556.3,-249.06 -556.3,-556.3"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3995"
inkscape:connector-curvature="0" /><path
d="m 2054.87,3399.29 c 0,-96.87 -78.53,-175.4 -175.41,-175.4 -96.87,0 -175.41,78.53 -175.41,175.4 0,96.88 78.54,175.41 175.41,175.41 96.88,0 175.41,-78.53 175.41,-175.41 z m -681.59,195.46 c 0,-201.31 106.95,-377.63 267.11,-475.29 84.05,-51 182.67,-80.36 288.16,-80.36 307.23,0 556.29,249.06 556.29,556.29 0,201.31 -106.93,377.62 -267.09,475.29 -84.05,51 -182.68,80.37 -288.17,80.37 -307.23,0 -556.3,-249.07 -556.3,-556.3"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3997"
inkscape:connector-curvature="0" /><path
d="m 1704.05,3399.29 c 0,-96.87 78.54,-175.4 175.41,-175.4 96.88,0 175.41,78.53 175.41,175.4 0,96.88 -78.53,175.41 -175.41,175.41 -96.87,0 -175.41,-78.53 -175.41,-175.41"
style="fill:#211c1d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3999"
inkscape:connector-curvature="0" /><path
d="m 3403.02,3810.25 c 0,-96.87 78.53,-175.41 175.4,-175.41 96.88,0 175.41,78.54 175.41,175.41 0,96.88 -78.53,175.41 -175.41,175.41 -96.87,0 -175.4,-78.53 -175.4,-175.41"
style="fill:#211c1d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4001"
inkscape:connector-curvature="0" /><path
d="m 1396.75,4482.59 c -19.42,4.05 -30.3,5.3 -34.76,5.67 -74.01,-4.57 -141.85,47.19 -155.52,122.25 -1.39,7.63 -1.98,15.2 -2.19,22.72 -40.26,-22.84 -80.55,-47.55 -118.26,-73.65 l -67.06,-46.43 -49.339,64.96 c -14.867,19.57 -83.508,112.19 -146.766,234.02 -118.808,-56.06 -211.628,-117.35 -234.285,-175.41 -4.289,-10.99 -2.554,-16.93 1.895,-23.45 19.394,-28.38 134.422,-115.17 806.285,-130.68"
style="fill:#588e2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4003"
inkscape:connector-curvature="0" /><path
d="m 4575.9,5583.11 c -22.32,-133.03 -65.22,-279.06 -93.67,-318.9 l -26.7,-37.35 c 120.88,58.85 228.71,114.68 320.24,166 318.25,178.44 357.82,256.58 362.37,276.29 2.98,12.9 -0.19,16.88 -1.54,18.59 -3.47,4.34 -25.81,26.03 -126.33,26.03 -109.85,0 -263.63,-25.12 -424.12,-59.95 -2.79,-22.91 -6.18,-46.46 -10.25,-70.71"
style="fill:#588e2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4005"
inkscape:connector-curvature="0" /><path
d="m 4451.83,5225.06 -45.9,3.74 c -0.84,0.07 -85.1,6.82 -199.36,6.82 -118.71,0 -275.22,-7.16 -403.66,-37.57 24.52,-50.97 18.97,-113.7 -19.55,-160.04 -31.48,-37.89 -84.66,-101.04 -148.35,-173.48 112.97,45.85 229.54,94.62 346.5,145.34 171.58,74.39 329.74,146.83 470.32,215.19"
style="fill:#588e2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4007"
inkscape:connector-curvature="0" /><path
d="m 1403.64,5358.88 c 136.88,-36.95 291.64,-55.68 459.99,-55.68 654.08,0 1373.77,283.13 1652.83,404.86 l 17.66,7.7 c -2.7,42.07 0.91,87.42 10.91,132.9 17.89,81.42 53.35,150.41 96.9,196.11 -8.4,31.22 -15.31,54.03 -20.13,65.61 -93.14,49.65 -861.11,335.72 -1261.61,335.72 -40.01,0 -74.95,-2.98 -103.85,-8.89 -354.96,-72.44 -894.3,-689.51 -913.67,-776.99 -5.81,-37.84 -4.05,-156.66 0.2,-284.94 l 60.77,-16.4"
style="fill:#588e2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4009"
inkscape:connector-curvature="0" /><path
d="m 2791.69,4672.82 c 59,37.56 134.37,28.46 182.85,-17.68 7.47,1.18 20.17,4.36 39,12.84 73.54,34.95 338.83,318.17 540.36,560.7 7.25,8.72 15.33,16.32 23.97,22.91 C 3117.3,5052.58 2473.75,4835.08 1861,4835.08 c -98.49,0 -192,5.75 -278.81,16.98 l 13.45,-39.61 -76.62,-29.35 c -0.56,-0.22 -13.73,-5.3 -35.76,-14.46 98.63,-23.04 231.97,-68.34 399.43,-135.98 306.53,-123.79 423.76,-128.51 453.09,-126.77 41.69,22.09 92.06,22.95 135.17,1.89 79.51,5.09 141.36,10.02 178.36,13.92 16.82,1.77 41.82,7 73.63,15.22 -3.51,52.66 21.08,105.57 68.75,135.9"
style="fill:#588e2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4011"
inkscape:connector-curvature="0" /><path
d="m 3550.54,5629.93 c -8.93,-3.9 -18.27,-7.93 -27.79,-12.02 -2.06,-0.88 -4.09,-1.76 -6.17,-2.65 -9.5,-4.07 -19.23,-8.21 -29.28,-12.45 -1.67,-0.7 -3.38,-1.42 -5.07,-2.13 -9.2,-3.87 -18.63,-7.8 -28.26,-11.79 -1.87,-0.78 -3.69,-1.54 -5.57,-2.31 -10.67,-4.41 -21.62,-8.89 -32.79,-13.43 -2.35,-0.96 -4.73,-1.92 -7.11,-2.88 -11.45,-4.64 -23.08,-9.32 -35.03,-14.07 -0.22,-0.08 -0.42,-0.17 -0.64,-0.25 -11.99,-4.77 -24.32,-9.6 -36.8,-14.47 -2.68,-1.04 -5.36,-2.09 -8.07,-3.14 -12.41,-4.82 -25.02,-9.67 -37.88,-14.56 -1.87,-0.71 -3.78,-1.43 -5.67,-2.14 -11.93,-4.52 -24.05,-9.07 -36.34,-13.65 -2.28,-0.84 -4.52,-1.69 -6.82,-2.54 -13.35,-4.94 -26.93,-9.91 -40.68,-14.89 -2.82,-1.03 -5.66,-2.05 -8.5,-3.07 -13.79,-4.97 -27.72,-9.95 -41.89,-14.93 -0.53,-0.19 -1.06,-0.38 -1.6,-0.57 -14.47,-5.09 -29.19,-10.18 -44.05,-15.27 -3.13,-1.08 -6.26,-2.15 -9.41,-3.23 -14.79,-5.03 -29.72,-10.07 -44.85,-15.08 -2.01,-0.67 -4.04,-1.33 -6.05,-1.99 -13.94,-4.61 -28.02,-9.19 -42.24,-13.76 -2.85,-0.92 -5.69,-1.84 -8.55,-2.76 -15.38,-4.92 -30.91,-9.81 -46.59,-14.67 -3.19,-0.99 -6.39,-1.97 -9.59,-2.95 -15.41,-4.75 -30.92,-9.46 -46.59,-14.13 -0.98,-0.3 -1.94,-0.59 -2.92,-0.88 -16.28,-4.84 -32.74,-9.63 -49.29,-14.37 -3.56,-1.02 -7.12,-2.04 -10.69,-3.05 -16.51,-4.7 -33.11,-9.35 -49.87,-13.93 -2.06,-0.56 -4.14,-1.11 -6.2,-1.67 -15.57,-4.23 -31.24,-8.4 -47,-12.52 -3.08,-0.8 -6.15,-1.61 -9.23,-2.41 -16.9,-4.38 -33.9,-8.68 -51,-12.91 -3.44,-0.84 -6.88,-1.68 -10.32,-2.52 -16.45,-4.02 -32.96,-7.99 -49.57,-11.85 -1.42,-0.33 -2.83,-0.68 -4.25,-1.01 -17.49,-4.05 -35.09,-7.98 -52.74,-11.84 -3.85,-0.84 -7.69,-1.68 -11.55,-2.51 -17.65,-3.81 -35.35,-7.54 -53.14,-11.14 -2.04,-0.41 -4.08,-0.8 -6.12,-1.21 -16.5,-3.31 -33.05,-6.5 -49.65,-9.62 -3.49,-0.65 -6.96,-1.31 -10.44,-1.96 -17.72,-3.27 -35.49,-6.42 -53.3,-9.44 -3.58,-0.61 -7.17,-1.2 -10.76,-1.8 -16.87,-2.81 -33.77,-5.53 -50.71,-8.11 -1.88,-0.29 -3.76,-0.59 -5.64,-0.88 -18.07,-2.72 -36.18,-5.27 -54.32,-7.71 -4.04,-0.54 -8.07,-1.08 -12.12,-1.6 -18.19,-2.39 -36.41,-4.65 -54.65,-6.73 -1.86,-0.21 -3.73,-0.39 -5.59,-0.6 -17.01,-1.9 -34.02,-3.65 -51.04,-5.27 -3.68,-0.35 -7.36,-0.71 -11.03,-1.05 -18,-1.64 -36.01,-3.13 -54,-4.44 -3.59,-0.26 -7.18,-0.49 -10.77,-0.74 -16.85,-1.16 -33.69,-2.19 -50.52,-3.04 -2.17,-0.11 -4.34,-0.25 -6.51,-0.36 -18.12,-0.87 -36.21,-1.51 -54.28,-2.01 -4.06,-0.11 -8.12,-0.21 -12.18,-0.3 -18.18,-0.41 -36.35,-0.68 -54.46,-0.69 -0.39,0 -0.78,-0.02 -1.17,-0.02 -1.18,0 -2.36,0.05 -3.54,0.05 -17.34,0.03 -34.63,0.28 -51.89,0.69 -3.59,0.09 -7.19,0.15 -10.78,0.25 -17.94,0.52 -35.83,1.25 -53.66,2.2 -3.54,0.19 -7.07,0.42 -10.61,0.63 -17.15,1 -34.26,2.18 -51.29,3.6 -1.55,0.13 -3.1,0.23 -4.65,0.36 -17.92,1.55 -35.75,3.4 -53.52,5.43 -3.88,0.45 -7.76,0.9 -11.64,1.36 -17.61,2.13 -35.15,4.46 -52.59,7.09 -2.43,0.37 -4.84,0.78 -7.26,1.16 -16.15,2.5 -32.22,5.25 -48.21,8.2 -3.02,0.56 -6.05,1.08 -9.07,1.65 -17.12,3.26 -34.12,6.82 -51.03,10.62 -3.57,0.8 -7.12,1.64 -10.68,2.46 -17.37,4.03 -34.66,8.25 -51.78,12.87 v 0 c 15.94,-24.13 31.74,-49.88 47.37,-77.34 56.81,-99.78 98.37,-198.36 121,-256.53 9.85,-1.54 20.08,-3.05 30.68,-4.5 3.4,-0.46 7.07,-0.89 10.55,-1.34 7.37,-0.97 14.7,-1.94 22.42,-2.84 4.17,-0.49 8.63,-0.93 12.9,-1.4 7.36,-0.81 14.63,-1.64 22.28,-2.39 4.87,-0.47 10.05,-0.88 15.05,-1.33 7.41,-0.67 14.71,-1.36 22.39,-1.96 5.49,-0.43 11.3,-0.78 16.93,-1.18 7.53,-0.52 14.94,-1.08 22.72,-1.54 6.03,-0.36 12.37,-0.62 18.55,-0.93 7.76,-0.4 15.42,-0.82 23.41,-1.14 6.45,-0.26 13.21,-0.41 19.81,-0.61 8.08,-0.25 16.07,-0.54 24.38,-0.71 6.9,-0.14 14.1,-0.17 21.16,-0.25 8.4,-0.1 16.69,-0.23 25.3,-0.24 0.91,0 1.76,-0.03 2.67,-0.03 13.07,0 26.45,0.13 40.03,0.35 3.51,0.05 7.12,0.15 10.66,0.23 11.55,0.23 23.27,0.54 35.18,0.93 4.76,0.16 9.54,0.33 14.36,0.52 12.51,0.48 25.22,1.06 38.12,1.74 3.35,0.17 6.62,0.31 10,0.5 16.07,0.9 32.47,1.97 49.14,3.18 4.16,0.31 8.42,0.67 12.62,0.99 13.01,1.01 26.18,2.11 39.55,3.32 5.34,0.48 10.69,0.98 16.08,1.49 14.44,1.38 29.08,2.89 43.92,4.52 3.43,0.38 6.77,0.7 10.22,1.09 18.09,2.05 36.53,4.3 55.22,6.73 4.84,0.63 9.78,1.33 14.66,1.99 14.41,1.93 28.98,3.98 43.74,6.16 5.98,0.88 11.97,1.77 18.01,2.69 16.46,2.51 33.14,5.17 50.02,7.99 3.39,0.57 6.69,1.08 10.09,1.65 20.13,3.42 40.61,7.09 61.35,10.97 5.49,1.02 11.08,2.13 16.62,3.18 15.89,3.04 31.95,6.22 48.19,9.53 6.54,1.33 13.08,2.67 19.67,4.05 18.59,3.89 37.41,7.96 56.46,12.22 3.28,0.73 6.48,1.41 9.77,2.15 22.12,5.01 44.61,10.32 67.34,15.85 6.28,1.52 12.65,3.14 18.97,4.7 17.26,4.28 34.68,8.71 52.27,13.29 7.18,1.87 14.35,3.73 21.58,5.65 21,5.58 42.22,11.36 63.71,17.39 2.83,0.8 5.6,1.53 8.45,2.34 24.19,6.83 48.76,14.03 73.56,21.45 6.98,2.09 14.06,4.28 21.09,6.42 18.72,5.69 37.62,11.55 56.68,17.59 7.74,2.45 15.45,4.89 23.24,7.39 23.62,7.6 47.46,15.43 71.6,23.57 2.23,0.75 4.4,1.45 6.64,2.2 26.25,8.9 52.9,18.2 79.77,27.75 7.69,2.74 15.48,5.57 23.23,8.36 20.22,7.28 40.6,14.76 61.17,22.42 8.26,3.08 16.5,6.14 24.82,9.28 26.48,10 53.18,20.25 80.23,30.9 1.4,0.54 2.75,1.05 4.15,1.61 28.32,11.17 57.04,22.81 85.98,34.71 8.4,3.45 16.89,7.01 25.34,10.53 21.77,9.05 43.71,18.32 65.83,27.79 8.74,3.75 17.47,7.47 26.27,11.28 29.89,12.96 59.98,26.17 90.5,39.9 12.71,39.9 29.61,89.87 50.57,145.38 -1.63,-0.06 -3.26,-0.35 -4.89,-0.35 -8.6,0 -17.21,0.93 -25.55,2.76 -48.63,10.69 -86.01,50.19 -106.69,111.28"
style="fill:#dec795;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4013"
inkscape:connector-curvature="0" /><path
d="m 1864.8,5217.98 c -1.57,0 -3.14,0.03 -4.71,0.03 1.18,0 2.36,-0.05 3.54,-0.05 0.39,0 0.78,0.02 1.17,0.02"
style="fill:#588e2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4015"
inkscape:connector-curvature="0" /><path
d="m 1018.35,5494.06 h -0.01 l 0.01,-42.62 z"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4017"
inkscape:connector-curvature="0" /><path
d="m 3785.29,6101.17 c 51.98,-11.42 91.37,-55.46 110.95,-123.96 3.12,-10.96 5.5,-22.52 7.5,-34.33 119.4,168.02 249.63,252.97 388.85,252.97 58.58,0 110.01,-13.8 153.14,-40.47 73.34,89.18 120,150.69 120,150.69 -55.13,-10.02 -170.4,-25.06 -170.4,-25.06 436.01,160.38 400.93,596.39 400.93,596.39 0,-75.17 -225.52,-255.59 -225.52,-255.59 10.02,65.15 -25.06,150.35 -25.06,150.35 10.02,-85.2 -260.61,-305.72 -260.61,-305.72 20.05,40.1 5.01,110.26 5.01,110.26 -15.03,-80.19 -135.31,-110.26 -135.31,-110.26 75.17,90.21 215.5,566.33 110.25,596.4 -105.24,30.06 -250.58,-310.73 -250.58,-310.73 -5.01,80.19 -50.12,80.19 -50.12,80.19 20.05,-250.59 -180.42,-451.05 -180.42,-451.05 -15.03,50.11 -95.22,75.17 -95.22,75.17 18.64,-40.39 8.39,-184.76 -2.09,-288.69 -4,-39.57 -8,-73.14 -10.48,-93 26.6,18.78 55.04,29.2 83.64,29.2 8.6,0 17.2,-0.92 25.54,-2.76"
style="fill:#dec795;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4019"
inkscape:connector-curvature="0" /><path
d="m 3675.53,5601.9 c 16.37,-3.62 36.26,5.07 56.1,23.61 13.18,30.75 27.34,62.15 42.53,93.64 13.99,29 28.16,56.65 42.51,83.02 10.33,54.85 9.63,109.48 -2.41,151.63 -10.25,35.9 -27.91,59.86 -47.26,64.12 -2.38,0.53 -4.76,0.78 -7.25,0.78 -43.49,0 -106.7,-75.68 -131.47,-188.34 -12.98,-59.03 -13,-118.94 -0.03,-164.34 10.25,-35.9 27.92,-59.86 47.28,-64.12"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4021"
inkscape:connector-curvature="0" /><path
d="m 4297.65,5829.03 -0.97,0.46 -0.45,0.2 c 0.07,-0.09 0.12,-0.2 0.2,-0.28 0.04,-0.02 0.07,-0.09 0.11,-0.11 0.21,-0.09 0.42,-0.18 0.65,-0.22 l 0.46,-0.05"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4023"
inkscape:connector-curvature="0" /><path
d="m 4378.39,5804.7 c -2.39,-29.65 -10.07,-54.09 -18.43,-76.25 -8.51,-22.11 -18.16,-41.71 -27.78,-59.26 -19.36,-35.02 -38.84,-61.72 -53.31,-79.81 -14.34,-18.14 -23.87,-27.54 -23.87,-27.54 0,0 3.02,13.01 8.7,35.1 5.47,22.16 13.76,53.42 22.44,90.17 4.3,18.34 8.62,38.12 11.99,58.52 3.48,20.28 5.71,41.7 4.67,60.26 -0.82,8.99 -2.51,17.11 -4.8,21.21 -0.46,1.06 -0.94,1.86 -1.46,2.2 -0.07,0.02 -0.14,0.03 -0.2,0.06 -0.26,0.13 -0.4,0.38 -0.6,0.56 l -3.36,1.55 -10.68,2.88 c -4.53,1.47 -8.89,1.41 -13.29,2.49 -4.39,0.79 -8.62,0.3 -12.92,0.76 -4.23,-0.36 -8.41,-0.76 -12.6,-1.27 -16.63,-2.68 -33.31,-10.8 -49.63,-22.65 -16.19,-11.99 -31.54,-27.5 -45.51,-44.14 -27.9,-33.56 -50.92,-70.59 -70.19,-102.9 -19.12,-32.52 -34.64,-60.78 -45.7,-80.69 -11.09,-20.13 -17.42,-31.63 -17.42,-31.63 0,0 -0.19,3.34 -0.09,9.56 0.25,6.18 0.17,15.41 1.35,26.89 1.81,23.12 6.17,56.01 16.44,94.71 10.48,38.59 26.33,83.33 54.52,128.2 14.19,22.31 31.68,44.81 54.99,64.45 22.97,19.69 53.12,36.24 87.3,42.26 8.48,1.21 17.17,1.79 25.71,2.09 8.47,-0.53 17.17,-0.49 25.36,-1.94 8.07,-1.67 16.62,-2.63 24.11,-5.42 l 11.37,-3.9 5.64,-1.99 0.7,-0.25 0.35,-0.13 3.98,-1.73 1.04,-0.56 2.1,-1.11 c 1.58,-0.13 21.95,-12.93 27.13,-21.21 l 5.49,-6.97 4.16,-7.25 c 2.91,-4.94 4.84,-9.74 6.38,-14.48 6.42,-19.14 6.85,-35.84 5.92,-50.84 z m -85.8,305.91 c -336.87,0 -552.93,-688.23 -594.16,-831.1 11.99,-2.44 23.73,-6.51 35.01,-11.97 144.62,43.29 331.78,53.32 473.13,53.32 119.6,0 206.3,-7.1 206.3,-7.1 37.59,52.62 255.6,796.85 -120.28,796.85"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4025"
inkscape:connector-curvature="0" /><path
d="m 4295.86,5830.24 c -0.25,0 -0.42,0.04 -0.57,0.1 0.12,-0.17 0.3,-0.28 0.45,-0.42 l 0.49,-0.23 c -0.13,0.18 -0.27,0.35 -0.37,0.55"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4027"
inkscape:connector-curvature="0" /><path
d="m 4296.23,5829.69 -0.49,0.23 c 0.2,-0.18 0.34,-0.43 0.6,-0.56 0.06,-0.03 0.13,-0.04 0.2,-0.06 -0.04,0.02 -0.07,0.09 -0.11,0.11 -0.08,0.08 -0.13,0.19 -0.2,0.28"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4029"
inkscape:connector-curvature="0" /><path
d="m 2966.29,4446 c 40.58,0 85.21,10.82 132.65,32.17 98.89,44.51 340.3,286.89 615.05,617.5 10.05,12.1 14.8,27.41 13.34,43.09 -1.44,15.68 -8.91,29.87 -21.01,39.92 -13.55,11.26 -27.92,13.63 -37.6,13.63 -17.63,0 -34.2,-7.75 -45.44,-21.29 -119.61,-143.94 -455.36,-529.55 -571.01,-584.52 l -1.71,-0.79 c -22.52,-10.13 -43.38,-16.75 -62.01,-19.68 l -43.96,-6.91 -32.23,30.67 c -10.81,10.28 -25.64,16.17 -40.73,16.17 -11.12,0 -22,-3.21 -31.51,-9.25 -13.29,-8.45 -22.48,-21.57 -25.9,-36.95 -3.41,-15.37 -0.63,-31.15 7.82,-44.44 4.51,-7.09 46.92,-69.32 144.25,-69.32"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4031"
inkscape:connector-curvature="0" /><path
d="m 2405.75,4433.04 c -9.68,0 -19.27,-2.38 -27.72,-6.86 l -17.32,-9.18 -19.57,-1.16 c -3.77,-0.22 -8.44,-0.39 -14.09,-0.39 -55.05,0 -190.36,17.35 -478.14,133.57 -317.34,128.16 -443.05,147.31 -489.74,147.31 -8.89,0 -14.11,-0.72 -16.49,-1.15 -15.49,-2.82 -28.96,-11.49 -37.93,-24.44 -8.95,-12.94 -12.35,-28.61 -9.53,-44.07 5.02,-27.64 29.84,-48.48 57.69,-48.48 1.16,0 2.34,0.03 3.53,0.1 l 6.51,0.41 6.51,-0.54 c 34.99,-2.91 147.46,-22.23 435.31,-138.47 232.71,-93.98 408.93,-141.64 523.78,-141.64 60.15,0 101.36,12.9 122.51,38.38 10.06,12.11 14.78,27.41 13.33,43.09 -1.45,15.68 -8.93,29.86 -21.03,39.91 -13.56,11.24 -27.94,13.61 -37.61,13.61"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4033"
inkscape:connector-curvature="0" /><path
d="m 983.938,5022.49 c -8.153,16.52 -16.125,35.07 -22.481,56.26 -5.801,21.44 -11.559,44.96 -8.769,74.3 1.355,14.54 5.167,30.93 14.937,47.19 9.523,16.37 26.316,30.48 43.445,37.51 l 3.24,1.45 1.63,0.72 5.51,1.62 4.17,1.13 4.18,1.13 c 1.59,0.4 6.08,0.9 9.07,1.16 3.34,0.29 6.73,0.44 10.1,0.46 l 5.02,-0.07 3.74,-0.5 c 4.93,-0.77 9.96,-1.69 14.76,-2.84 18.12,-5.46 32.24,-13.91 44.48,-22.63 23.61,-18.16 40.6,-37.99 55.55,-58.16 14.99,-20.03 27.23,-40.58 38.14,-60.67 21.58,-40.27 37.1,-79.27 48.25,-113.39 11.22,-34.09 17.96,-63.32 21.76,-84.06 2.17,-10.25 3.04,-18.62 3.93,-24.19 0.64,-5.67 0.98,-8.69 0.98,-8.69 0,0 -7.84,9.39 -20.42,26.02 -12.74,16.54 -30.22,40.35 -50.4,68.76 -20.19,28.37 -43.19,61.42 -68.05,95.24 -12.46,16.84 -25.64,33.7 -39.07,49.72 -13.59,15.64 -27.77,31.07 -41.48,41.01 -6.59,4.99 -12.86,8.31 -16.96,9.85 -0.86,0.09 -1.56,0.14 -2.31,0.48 l -0.54,0.29 c 0.22,-0.07 0.45,-0.11 0.69,-0.11 0.48,-0.02 0.97,0.1 1.43,0.35 0.11,0.1 1.67,0.97 0.45,0.79 l -4.24,-0.86 -2.6,-0.53 c -3.5,-1.24 -5.47,-2.06 -7.89,-4.51 -2.48,-2.73 -5.05,-8.14 -7,-15.1 -3.92,-14.04 -3.93,-33.15 -2.92,-51 1.22,-18.17 3.69,-36.12 6.39,-52.82 5.49,-33.48 11.52,-62.25 15.47,-82.62 4.17,-20.31 6.41,-32.33 6.41,-32.33 0,0 -2.21,2.12 -5.99,6.36 -3.66,4.31 -9.45,10.45 -15.73,18.9 -13.03,16.7 -30.46,41.42 -46.882,74.38 z m 504.612,-159.78 c 0,0 -200.14,588.8 -470.25,588.73 -35.101,-0.01 -71.421,-9.96 -108.597,-32.44 -323.254,-195.45 127.797,-789.34 127.797,-789.34 195.46,135.32 451.05,233.05 451.05,233.05"
style="fill:#78d3e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4035"
inkscape:connector-curvature="0" /><path
d="m 2879.05,3040.41 c 3.26,0.54 6.47,1.16 9.7,1.76 3.58,0.66 7.13,1.35 10.66,2.08 142.77,29.38 247.77,111.82 248.93,194.35 0.08,5.76 -0.35,11.52 -1.3,17.26 -1.79,10.8 -5.4,21.05 -10.59,30.7 -1.92,3.59 -4.2,7.04 -6.57,10.45 -1.03,1.49 -2.12,2.95 -3.23,4.41 -1.13,1.48 -2.38,2.91 -3.59,4.36 -3.43,4.07 -7.15,8.01 -11.2,11.79 -0.02,0.03 -0.05,0.06 -0.08,0.09 -0.01,0.01 -0.02,0.01 -0.03,0.02 -3.17,2.97 -6.54,5.83 -10.07,8.61 -0.15,0.12 -0.3,0.23 -0.45,0.35 -17.52,13.67 -39.29,25.02 -64.36,33.71 -1.19,0.41 -2.36,0.84 -3.56,1.24 -4.03,1.34 -8.14,2.6 -12.32,3.8 -1.85,0.53 -3.71,1.04 -5.59,1.54 -3.94,1.06 -7.91,2.09 -11.98,3.02 -2.3,0.53 -4.66,1 -7,1.49 -3.88,0.82 -7.75,1.65 -11.73,2.35 -3.13,0.55 -6.35,0.99 -9.53,1.47 -5.64,0.85 -11.35,1.61 -17.16,2.24 -4.19,0.45 -8.38,0.92 -12.66,1.26 -3.01,0.24 -6.07,0.38 -9.12,0.56 -4.22,0.25 -8.46,0.47 -12.76,0.61 -3.05,0.09 -6.11,0.14 -9.2,0.17 -4.49,0.05 -9.02,0.04 -13.58,-0.03 -2.94,-0.05 -5.87,-0.1 -8.83,-0.2 -5.08,-0.17 -10.21,-0.46 -15.36,-0.79 -2.52,-0.16 -5.01,-0.28 -7.54,-0.48 -7.71,-0.61 -15.47,-1.36 -23.3,-2.33 -7.24,-0.9 -14.51,-1.9 -21.84,-3.11 -6.78,-1.13 -13.46,-2.42 -20.08,-3.78 -1.66,-0.34 -3.32,-0.69 -4.96,-1.04 -6.5,-1.4 -12.95,-2.87 -19.28,-4.48 -0.07,-0.02 -0.14,-0.04 -0.21,-0.05 -6.46,-1.65 -12.79,-3.45 -19.06,-5.31 -1.47,-0.44 -2.93,-0.88 -4.39,-1.33 -6.17,-1.89 -12.27,-3.85 -18.24,-5.94 -0.02,-0.01 -0.04,-0.02 -0.07,-0.02 -6.09,-2.14 -12.04,-4.4 -17.92,-6.73 -1.24,-0.5 -2.47,-1 -3.71,-1.5 -11.64,-4.74 -22.82,-9.84 -33.47,-15.28 -1.05,-0.53 -2.09,-1.07 -3.13,-1.62 -5.25,-2.73 -10.4,-5.52 -15.38,-8.41 -0.01,-0.01 -0.02,-0.01 -0.02,-0.01 0,0 -0.01,0 -0.01,-0.01 -4.42,-2.56 -8.71,-5.19 -12.9,-7.87 -0.78,-0.49 -1.52,-1 -2.28,-1.49 -3.28,-2.13 -6.49,-4.29 -9.62,-6.48 -1.06,-0.74 -2.09,-1.48 -3.13,-2.23 -2.91,-2.09 -5.76,-4.21 -8.53,-6.36 -0.9,-0.69 -1.81,-1.37 -2.69,-2.06 -7.17,-5.68 -13.88,-11.52 -20.07,-17.52 -0.68,-0.66 -1.33,-1.34 -2,-2 -2.34,-2.33 -4.62,-4.67 -6.8,-7.03 -0.84,-0.9 -1.65,-1.81 -2.46,-2.71 -2.03,-2.27 -3.97,-4.55 -5.85,-6.85 -0.7,-0.85 -1.41,-1.69 -2.08,-2.54 -2.42,-3.06 -4.74,-6.14 -6.89,-9.25 -0.03,-0.04 -0.06,-0.08 -0.08,-0.11 -2.21,-3.19 -4.24,-6.4 -6.15,-9.64 -0.51,-0.85 -0.96,-1.71 -1.45,-2.57 -1.34,-2.36 -2.61,-4.73 -3.79,-7.12 -0.52,-1.05 -1.03,-2.11 -1.52,-3.17 -1.08,-2.32 -2.07,-4.65 -3,-6.99 -0.38,-0.97 -0.79,-1.94 -1.15,-2.91 -1.17,-3.19 -2.23,-6.39 -3.11,-9.6 -0.02,-0.07 -0.05,-0.15 -0.07,-0.23 -0.89,-3.28 -1.59,-6.58 -2.16,-9.87 -0.18,-1 -0.29,-1.99 -0.43,-2.98 -0.34,-2.34 -0.61,-4.67 -0.79,-7.01 -0.09,-1.15 -0.15,-2.29 -0.2,-3.43 -0.09,-2.32 -0.09,-4.63 -0.02,-6.94 0.03,-1.03 0.03,-2.07 0.09,-3.1 0.21,-3.3 0.53,-6.59 1.08,-9.88 0.87,-5.27 2.22,-10.39 3.93,-15.39 28.02,-82.24 165.39,-127.46 319.29,-101.91"
style="fill:#211c1d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4037"
inkscape:connector-curvature="0" /><path
d="m 2521.85,3144.41 c 4.8,-28.85 22.03,-53.88 48.26,-74.1 2.7,-2.09 5.59,-4.08 8.52,-6.07 44.36,-30.36 110.53,-48.32 186.24,-48.98 29.69,-0.27 60.79,2.11 92.54,7.38 95.35,15.83 176.48,54.44 226.4,102.17 11.09,10.61 20.66,21.67 28.46,33.02 7.8,11.36 13.91,23.02 18.1,34.83 4.19,11.81 6.46,23.77 6.61,35.73 0.07,5.98 -0.36,11.96 -1.34,17.93 -3.97,23.85 -16.33,45.14 -35.29,63.22 -4.73,4.52 -9.89,8.85 -15.42,12.96 -11.09,8.21 -23.7,15.59 -37.6,22.05 -19.22,8.91 -41.11,15.92 -64.73,21.09 -10.62,2.32 -21.46,4.38 -32.8,5.89 -17.91,2.38 -36.7,3.68 -56.42,3.9 0,0 -0.36,0.04 -0.76,0.05 -19.75,0.17 -40.2,-0.83 -61,-3.08 -10.44,-1.12 -20.95,-2.56 -31.54,-4.31 -31.78,-5.28 -61.98,-13.09 -89.97,-22.92 -121.29,-42.61 -201.12,-123.25 -188.26,-200.76"
style="fill:#211c1d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4039"
inkscape:connector-curvature="0" /><path
d="m 2799.32,2390.59 c 10.63,0 21.57,2.16 32.87,6.84 53.5,22.09 55.85,115.25 43.49,204.99 -77.04,-24.64 -144.33,-62.43 -203.75,-98.09 32.47,-61.24 75.27,-113.74 127.39,-113.74"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4041"
inkscape:connector-curvature="0" /><path
d="m 3058.74,2452.64 c 8.78,-3.28 24.35,-6.48 42.26,-6.48 49.7,0 117.57,24.49 108.94,139.42 -0.76,10.23 -1.37,23.86 -1.95,38.57 -23.33,0.44 -47.39,0.58 -69.64,1.14 -38.4,0.96 -74.3,1.87 -105.04,1.87 -23.55,0 -43.27,-0.4 -57.75,-2.2 22.72,-81.15 52.48,-160.81 83.18,-172.32"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4043"
inkscape:connector-curvature="0" /><path
d="m 3260.73,3102.88 c 0,0 -93.7,-214.77 -351.38,-255.19 -67.15,-10.54 -124.22,-15.07 -172.69,-15.07 -137.51,0 -205.78,36.48 -238.51,75.7 0,0 -247.27,-70.74 -268.12,-222.35 -15.56,-113.36 96.95,-171.62 196.03,-171.62 33.45,0 65.34,6.64 90.3,20.02 98.93,53.06 247.24,169.29 445.04,194.55 17.88,2.29 42.58,3.09 71.91,3.08 67.69,0 159.94,-4.24 249.38,-4.24 101.71,0 199.81,5.5 253.92,28.97 122.31,53.06 122.31,144.02 114.54,189.49 -8.67,50.41 -83.33,154.14 -390.42,156.66"
style="fill:#dec795;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4045"
inkscape:connector-curvature="0" /></g></g></svg>
\ No newline at end of file
import { DataSourcePlugin } from '@grafana/data';
import { JaegerDatasource } from './datasource';
import { JaegerQueryField } from './QueryField';
import { ConfigEditor } from './ConfigEditor';
export const plugin = new DataSourcePlugin(JaegerDatasource)
.setConfigEditor(ConfigEditor)
.setExploreQueryField(JaegerQueryField);
{
"type": "datasource",
"name": "Jaeger",
"id": "jaeger",
"category": "tracing",
"metrics": false,
"alerting": false,
"annotations": false,
"logs": false,
"streaming": false,
"tracing": true,
"info": {
"description": "Open source, end-to-end distributed tracing",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
},
"logos": {
"small": "img/jaeger_logo.svg",
"large": "img/jaeger_logo.svg"
},
"links": [
{
"name": "Learn more",
"url": "https://www.jaegertracing.io"
},
{
"name": "GitHub Project",
"url": "https://github.com/jaegertracing/jaeger"
}
]
}
}
......@@ -4,7 +4,7 @@ import cx from 'classnames';
import { FormField } from '@grafana/ui';
import { DerivedFieldConfig } from '../types';
import { getLinksFromLogsField } from '../../../../features/panel/panellinks/linkSuppliers';
import { ArrayVector, FieldType } from '@grafana/data';
import { ArrayVector, Field, FieldType, LinkModel } from '@grafana/data';
type Props = {
derivedFields: DerivedFieldConfig[];
......@@ -90,7 +90,7 @@ function makeDebugFields(derivedFields: DerivedFieldConfig[], debugText: string)
try {
const testMatch = debugText.match(field.matcherRegex);
const value = testMatch && testMatch[1];
let link;
let link: LinkModel<Field>;
if (field.url && value) {
link = getLinksFromLogsField(
......@@ -103,7 +103,7 @@ function makeDebugFields(derivedFields: DerivedFieldConfig[], debugText: string)
},
},
0
)[0];
)[0].linkModel;
}
return {
......
import React from 'react';
import React, { useState } from 'react';
import { css } from 'emotion';
import { Button, FormField, DataLinkInput, stylesFactory } from '@grafana/ui';
import { Button, FormField, DataLinkInput, stylesFactory, Switch } from '@grafana/ui';
import { VariableSuggestion } from '@grafana/data';
import { DataSourceSelectItem } from '@grafana/data';
import { DerivedFieldConfig } from '../types';
import DataSourcePicker from 'app/core/components/Select/DataSourcePicker';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { config } from 'app/core/config';
const getStyles = stylesFactory(() => ({
firstRow: css`
row: css`
display: flex;
align-items: baseline;
`,
......@@ -27,6 +32,7 @@ type Props = {
export const DerivedField = (props: Props) => {
const { value, onChange, onDelete, suggestions, className } = props;
const styles = getStyles();
const [hasIntenalLink, setHasInternalLink] = useState(!!value.datasourceName);
const handleChange = (field: keyof typeof value) => (event: React.ChangeEvent<HTMLInputElement>) => {
onChange({
......@@ -37,7 +43,7 @@ export const DerivedField = (props: Props) => {
return (
<div className={className}>
<div className={styles.firstRow}>
<div className={styles.row}>
<FormField
className={styles.nameField}
labelWidth={5}
......@@ -93,6 +99,64 @@ export const DerivedField = (props: Props) => {
width: 100%;
`}
/>
{config.featureToggles.tracingIntegration && (
<div className={styles.row}>
<Switch
label="Internal link"
checked={hasIntenalLink}
onChange={() => {
if (hasIntenalLink) {
onChange({
...value,
datasourceName: undefined,
});
}
setHasInternalLink(!hasIntenalLink);
}}
/>
{hasIntenalLink && (
<DataSourceSection
onChange={datasourceName => {
onChange({
...value,
datasourceName,
});
}}
datasourceName={value.datasourceName}
/>
)}
</div>
)}
</div>
);
};
type DataSourceSectionProps = {
datasourceName?: string;
onChange: (name: string) => void;
};
const DataSourceSection = (props: DataSourceSectionProps) => {
const { datasourceName, onChange } = props;
const datasources: DataSourceSelectItem[] = getDatasourceSrv()
.getExternal()
.map(
(ds: any) =>
({
value: ds.name,
name: ds.name,
meta: ds.meta,
} as DataSourceSelectItem)
);
const selectedDatasource = datasourceName && datasources.find(d => d.name === datasourceName);
return (
<DataSourcePicker
onChange={newValue => {
onChange(newValue.name);
}}
datasources={datasources}
current={selectedDatasource}
/>
);
};
......@@ -51,6 +51,7 @@ import {
} from './types';
import { LegacyTarget, LiveStreams } from './live_streams';
import LanguageProvider from './language_provider';
import { serializeParams } from '../../../core/utils/fetch';
export type RangeQueryOptions = Pick<DataQueryRequest<LokiQuery>, 'range' | 'intervalMs' | 'maxDataPoints' | 'reverse'>;
export const DEFAULT_MAX_LINES = 1000;
......@@ -68,12 +69,6 @@ const DEFAULT_QUERY_PARAMS: Partial<LokiLegacyQueryRequest> = {
query: '',
};
function serializeParams(data: Record<string, any>) {
return Object.keys(data)
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`)
.join('&');
}
interface LokiContextQueryOptions {
direction?: 'BACKWARD' | 'FORWARD';
limit?: number;
......
......@@ -395,11 +395,16 @@ export const enhanceDataFrame = (dataFrame: DataFrame, config: LokiOptions | nul
const fields = derivedFields.reduce((acc, field) => {
const config: FieldConfig = {};
if (field.url) {
if (field.url || field.datasourceName) {
config.links = [
{
url: field.url,
title: '',
meta: field.datasourceName
? {
datasourceName: field.datasourceName,
}
: undefined,
},
];
}
......
......@@ -127,6 +127,7 @@ export type DerivedFieldConfig = {
matcherRegex: string;
name: string;
url?: string;
datasourceName?: string;
};
export interface TransformerOptions {
......
import React from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { DataSourceHttpSettings } from '@grafana/ui';
export type Props = DataSourcePluginOptionsEditorProps;
export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
return (
<DataSourceHttpSettings
defaultUrl={'http://localhost:3100'}
dataSourceConfig={options}
showAccessOptions={true}
onChange={onOptionsChange}
/>
);
};
import React from 'react';
import { ZipkinDatasource, ZipkinQuery } from './datasource';
import { ExploreQueryFieldProps } from '@grafana/data';
type Props = ExploreQueryFieldProps<ZipkinDatasource, ZipkinQuery>;
export const QueryField = (props: Props) => (
<div className={'slate-query-field__wrapper'}>
<div className="slate-query-field">
<input
style={{ width: '100%' }}
value={props.query.query || ''}
onChange={e =>
props.onChange({
...props.query,
query: e.currentTarget.value,
})
}
/>
</div>
</div>
);
import {
MutableDataFrame,
DataSourceApi,
DataSourceInstanceSettings,
DataQueryRequest,
DataQueryResponse,
DataQuery,
} from '@grafana/data';
import { Observable, of } from 'rxjs';
export type ZipkinQuery = {
query: string;
} & DataQuery;
export class ZipkinDatasource extends DataSourceApi<ZipkinQuery> {
constructor(instanceSettings: DataSourceInstanceSettings) {
super(instanceSettings);
}
query(options: DataQueryRequest<ZipkinQuery>): Observable<DataQueryResponse> {
return of({
data: [
new MutableDataFrame({
fields: [
{
name: 'url',
values: [],
},
],
}),
],
});
}
async testDatasource(): Promise<any> {
return true;
}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 418 442"><title>자산 1</title><g id="레이어_2" data-name="레이어 2"><g id="레이어_1-2" data-name="레이어 1"><image width="418" height="442" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAaIAAAG6CAYAAABKjkKZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQwIDc5LjE2MDQ1MSwgMjAxNy8wNS8wNi0wMTowODoyMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo5ZDlkMzkwMy0xOGJlLTQyMTYtYTkzOC0yZDkxNTIxOGU2M2EiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEFCM0I3OENDNjhEMTFFOTk2RTg4QzkzMzBFRTMwNjkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEFCM0I3OEJDNjhEMTFFOTk2RTg4QzkzMzBFRTMwNjkiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozQUYzQUMyOUFCMkExMUU5OTIxN0UzMTZDQjEzQkNFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDozQUYzQUMyQUFCMkExMUU5OTIxN0UzMTZDQjEzQkNFOSIvPiA8L3Jk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"/></g></g></svg>
\ No newline at end of file
import { DataSourcePlugin } from '@grafana/data';
import { ZipkinDatasource } from './datasource';
import { QueryField } from './QueryField';
import { ConfigEditor } from './ConfigEditor';
export const plugin = new DataSourcePlugin(ZipkinDatasource)
.setConfigEditor(ConfigEditor)
.setExploreQueryField(QueryField);
{
"type": "datasource",
"name": "Zipkin",
"id": "zipkin",
"category": "tracing",
"metrics": false,
"alerting": false,
"annotations": false,
"logs": false,
"streaming": false,
"tracing": true,
"info": {
"description": "Placeholder for the distributed tracing system.",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
},
"logos": {
"small": "img/zipkin-logo.svg",
"large": "img/zipkin-logo.svg"
},
"links": [
{
"name": "Learn more",
"url": "https://zipkin.io"
}
]
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment