src/datasource.ts (84 lines of code) (raw):
/**
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DataFrame, DataQueryRequest, DataQueryResponse, DataSourceInstanceSettings, ScopedVars } from '@grafana/data';
import { DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { CloudTraceOptions, Query } from './types';
import { CloudTraceVariableSupport } from './variables';
export class DataSource extends DataSourceWithBackend<Query, CloudTraceOptions> {
authenticationType: string;
constructor(
private instanceSettings: DataSourceInstanceSettings<CloudTraceOptions>,
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
) {
super(instanceSettings);
this.authenticationType = instanceSettings.jsonData.authenticationType || 'jwt';
this.variables = new CloudTraceVariableSupport(this);
}
/**
* Get the Project ID from GCE or we parsed from the data source's JWT token
*
* @returns Project ID from the provided JWT token
*/
async getDefaultProject() {
const { defaultProject, authenticationType } = this.instanceSettings.jsonData;
if (authenticationType === 'gce') {
await this.ensureGCEDefaultProject();
return this.instanceSettings.jsonData.gceDefaultProject || "";
}
return defaultProject || '';
}
async getGCEDefaultProject() {
return this.getResource(`gceDefaultProject`);
}
async ensureGCEDefaultProject() {
const { authenticationType, gceDefaultProject } = this.instanceSettings.jsonData;
if (authenticationType === 'gce' && !gceDefaultProject) {
this.instanceSettings.jsonData.gceDefaultProject = await this.getGCEDefaultProject();
}
}
/**
* Have the backend call `resourcemanager.projects.list` with our credentials,
* and return the IDs of all projects found
*
* @returns List of discovered project IDs
*/
getProjects(): Promise<string[]> {
return this.getResource(`projects`);
}
applyTemplateVariables(query: Query, scopedVars: ScopedVars): Query {
return {
...query,
queryText: this.templateSrv.replace(query.queryText, scopedVars),
projectId: this.templateSrv.replace(query.projectId, scopedVars),
traceId: this.templateSrv.replace(query.traceId, scopedVars),
};
}
/**
* Check's the Cloud Trace data query's hide property,
* and returns whether or not this query should be hidden
*
* @param query {@link Query} to check if hide is currently set
* @returns Boolean of whether or not to hide the attempted query
*/
filterQuery(query: Query): boolean {
return !query.hide;
}
/**
* After performing a query, performs post-processing on the result
*
* @param request {@link DataQueryRequest<Query>} a data query request
* @returns a modified {@link Obserservable<DataQueryResponse>}
*/
query(request: DataQueryRequest<Query>): Observable<DataQueryResponse> {
let response = super.query(request);
return response.pipe(
map((dataQueryResponse) => {
return {
...dataQueryResponse,
data: dataQueryResponse.data.flatMap((frame) => {
const query = request.targets.find((t) => t.refId === frame.refId);
return this.addLinksToTraceIdColumn(frame, query);
}),
};
})
);
}
/**
* Takes a response data frame, and adds links to the `Trace ID` field
* of it as long as it is a "traceTable" data frame. These links will perform
* a new traceID queryType query for this same datasource using the trace ID
* found in a given field
*
* @param request {@link DataQueryRequest<Query>} a data query request
* @returns a modified {@link Obserservable<DataQueryResponse>}
*/
addLinksToTraceIdColumn(response: DataFrame, query?: Query): DataFrame[] {
if (response.name !== "traceTable") {
return [response];
}
const idField = response.fields.find((f) => f.name === 'Trace ID');
idField!.config.links = [
{
title: 'Trace: ${__value.raw}',
url: '',
internal: {
datasourceUid: this.instanceSettings.uid,
datasourceName: this.instanceSettings.name,
query: {
...(query || {}),
traceId: '${__value.raw}',
queryType: 'traceID',
},
},
},
];
return [response];
}
}