Rename locations -> instances
Signed-off-by: Julio Zynger <julio.zynger@soundcloud.com>
This commit is contained in:
committed by
Fredrik Adelöw
parent
f6e22fb230
commit
171be275ae
@@ -20,15 +20,16 @@ annotations:
|
||||
periskop.io/name: '<THE NAME OF THE PERISKOP APP>'
|
||||
```
|
||||
|
||||
### Locations
|
||||
### Instances
|
||||
|
||||
The periskop plugin can be configured to fetch aggregated errors from multiple deployment locations. This is especially useful if you have a multi-zone deployment, or a federated setup and would like to drill deeper into a single instance of the federation. Each of the configured locations will be included in the plugin's UI via a dropdown on the errors table.
|
||||
The periskop plugin can be configured to fetch aggregated errors from multiple deployment instances.
|
||||
This is especially useful if you have a multi-zone deployment, or a federated setup and would like to drill deeper into a single instance of the federation. Each of the configured instances will be included in the plugin's UI via a dropdown on the errors table.
|
||||
|
||||
The plugin requires to configure _at least one_ Periskop API location in the [app-config.yaml](https://github.com/backstage/backstage/blob/master/app-config.yaml):
|
||||
|
||||
```yaml
|
||||
periskop:
|
||||
locations:
|
||||
- name: <name of the location>
|
||||
host: <HTTP/S host for the Periskop API location>
|
||||
instances:
|
||||
- name: <name of the instance>
|
||||
host: <HTTP/S host for the Periskop API instance>
|
||||
```
|
||||
|
||||
Vendored
+1
-1
@@ -23,7 +23,7 @@ export interface Config {
|
||||
* Integration configuration for the periskop servers
|
||||
* @visibility frontend
|
||||
*/
|
||||
locations: Array<{
|
||||
instances: Array<{
|
||||
/**
|
||||
* The name of the given Periskop instance
|
||||
* @visibility frontend
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
|
||||
import { ConfigApi, DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { AggregatedError, NotFoundInLocation } from '../types';
|
||||
import { AggregatedError, NotFoundInInstance } from '../types';
|
||||
|
||||
type Options = {
|
||||
discoveryApi: DiscoveryApi;
|
||||
configApi: ConfigApi;
|
||||
};
|
||||
|
||||
type PeriskopLocation = {
|
||||
type PeriskopInstance = {
|
||||
name: string;
|
||||
host: string;
|
||||
};
|
||||
@@ -34,12 +34,12 @@ type PeriskopLocation = {
|
||||
*/
|
||||
export class PeriskopApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
private readonly locations: PeriskopLocation[];
|
||||
private readonly instances: PeriskopInstance[];
|
||||
|
||||
constructor(options: Options) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
this.locations = options.configApi
|
||||
.getConfigArray('periskop.locations')
|
||||
this.instances = options.configApi
|
||||
.getConfigArray('periskop.instances')
|
||||
.flatMap(locConf => {
|
||||
const name = locConf.getString('name');
|
||||
const host = locConf.getString('host');
|
||||
@@ -47,31 +47,32 @@ export class PeriskopApi {
|
||||
});
|
||||
}
|
||||
|
||||
private getApiUrl(locationName: string): string | undefined {
|
||||
return this.locations.find(loc => loc.name === locationName)?.host;
|
||||
private getApiUrl(instanceName: string): string | undefined {
|
||||
return this.instances.find(instance => instance.name === instanceName)
|
||||
?.host;
|
||||
}
|
||||
|
||||
getLocationNames(): string[] {
|
||||
return this.locations.map(e => e.name);
|
||||
getInstanceNames(): string[] {
|
||||
return this.instances.map(e => e.name);
|
||||
}
|
||||
|
||||
getErrorInstanceUrl(
|
||||
locationName: string,
|
||||
instanceName: string,
|
||||
serviceName: string,
|
||||
error: AggregatedError,
|
||||
): string {
|
||||
return `${this.getApiUrl(
|
||||
locationName,
|
||||
instanceName,
|
||||
)}/#/${serviceName}/errors/${encodeURIComponent(error.aggregation_key)}`;
|
||||
}
|
||||
|
||||
async getErrors(
|
||||
locationName: string,
|
||||
instanceName: string,
|
||||
serviceName: string,
|
||||
): Promise<AggregatedError[] | NotFoundInLocation> {
|
||||
): Promise<AggregatedError[] | NotFoundInInstance> {
|
||||
const apiUrl = `${await this.discoveryApi.getBaseUrl(
|
||||
'periskop',
|
||||
)}/${locationName}/${serviceName}`;
|
||||
)}/${instanceName}/${serviceName}`;
|
||||
const response = await fetch(apiUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { periskopApiRef } from '../..';
|
||||
import { AggregatedError, NotFoundInLocation } from '../../types';
|
||||
import { AggregatedError, NotFoundInInstance } from '../../types';
|
||||
|
||||
/**
|
||||
* Constant storing Periskop project name.
|
||||
@@ -72,10 +72,10 @@ const renderLastOccurrence = (error: AggregatedError): React.ReactNode => {
|
||||
return moment(new Date(error.latest_errors[0].timestamp * 1000)).fromNow();
|
||||
};
|
||||
|
||||
function isNotFoundInLocation(
|
||||
apiResult: AggregatedError[] | NotFoundInLocation | undefined,
|
||||
): apiResult is NotFoundInLocation {
|
||||
return (apiResult as NotFoundInLocation)?.body !== undefined;
|
||||
function isNotFoundInInstance(
|
||||
apiResult: AggregatedError[] | NotFoundInInstance | undefined,
|
||||
): apiResult is NotFoundInInstance {
|
||||
return (apiResult as NotFoundInInstance)?.body !== undefined;
|
||||
}
|
||||
|
||||
export const PeriskopErrorsTable = () => {
|
||||
@@ -86,17 +86,17 @@ export const PeriskopErrorsTable = () => {
|
||||
| undefined) ?? entity.metadata.name;
|
||||
|
||||
const periskopApi = useApi(periskopApiRef);
|
||||
const locations = periskopApi.getLocationNames();
|
||||
const [locationOption, setLocationOption] = React.useState<string>(
|
||||
locations[0],
|
||||
const instanceNames = periskopApi.getInstanceNames();
|
||||
const [instanceOption, setInstanceOption] = React.useState<string>(
|
||||
instanceNames[0],
|
||||
);
|
||||
const {
|
||||
value: aggregatedErrors,
|
||||
loading,
|
||||
error,
|
||||
} = useAsync(async (): Promise<AggregatedError[] | NotFoundInLocation> => {
|
||||
return periskopApi.getErrors(locationOption, entityPeriskopName);
|
||||
}, [locationOption]);
|
||||
} = useAsync(async (): Promise<AggregatedError[] | NotFoundInInstance> => {
|
||||
return periskopApi.getErrors(instanceOption, entityPeriskopName);
|
||||
}, [instanceOption]);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
@@ -112,7 +112,7 @@ export const PeriskopErrorsTable = () => {
|
||||
sorting: false,
|
||||
render: aggregatedError => {
|
||||
const errorUrl = periskopApi.getErrorInstanceUrl(
|
||||
locationOption,
|
||||
instanceOption,
|
||||
entityPeriskopName,
|
||||
aggregatedError,
|
||||
);
|
||||
@@ -138,13 +138,13 @@ export const PeriskopErrorsTable = () => {
|
||||
|
||||
const sortingSelect = (
|
||||
<Select
|
||||
selected={locationOption}
|
||||
label="Location"
|
||||
items={locations.map(e => ({
|
||||
selected={instanceOption}
|
||||
label="Instance"
|
||||
items={instanceNames.map(e => ({
|
||||
label: e,
|
||||
value: e,
|
||||
}))}
|
||||
onChange={el => setLocationOption(el.toString())}
|
||||
onChange={el => setInstanceOption(el.toString())}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -154,7 +154,7 @@ export const PeriskopErrorsTable = () => {
|
||||
</ContentHeader>
|
||||
);
|
||||
|
||||
if (isNotFoundInLocation(aggregatedErrors)) {
|
||||
if (isNotFoundInInstance(aggregatedErrors)) {
|
||||
return (
|
||||
<Content noPadding>
|
||||
{contentHeader}
|
||||
|
||||
@@ -43,6 +43,6 @@ export interface RequestHeaders {
|
||||
[k: string]: string;
|
||||
}
|
||||
|
||||
export interface NotFoundInLocation {
|
||||
export interface NotFoundInInstance {
|
||||
body: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user