Skip to content

Wire up components to Metrics List Index

Daniele Rossetti requested to merge rossetd/metrics-list-ui into master

What does this MR do and why?

Hooking up missing components to the Metrics List UI

  • Add ProvisionedObservabilityContainer
  • Add MetricsList

Closes gitlab-org/opstrace/opstrace#2437 (closed) , gitlab-org/opstrace/opstrace#2470 (closed)

Screenshots or screen recordings

image image

How to set up and validate locally

  • Enable :observability_metrics feature flag
Apply patch to load mocks
diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js
index 2f25184e9d6b..491454fa90ec 100644
--- a/app/assets/javascripts/observability/client.js
+++ b/app/assets/javascripts/observability/client.js
@@ -1,18 +1,27 @@
 import * as Sentry from '~/sentry/sentry_browser_wrapper';
 import axios from '~/lib/utils/axios_utils';
+// import mockData from './mock_traces.json';
 
 function reportErrorAndThrow(e) {
   Sentry.captureException(e);
   throw e;
 }
+
+function mockReturnDataWithDelay(data) {
+  return new Promise((resolve) => {
+    setTimeout(() => resolve(data), 500);
+  });
+}
+
 // Provisioning API spec: https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/provisioning-api/pkg/provisioningapi/routes.go#L59
 async function enableObservability(provisioningUrl) {
   try {
     // Note: axios.put(url, undefined, {withCredentials: true}) does not send cookies properly, so need to use the API below for the correct behaviour
-    return await axios(provisioningUrl, {
-      method: 'put',
-      withCredentials: true,
-    });
+    // return await axios(provisioningUrl, {
+    //   method: 'put',
+    //   withCredentials: true,
+    // });
+    return mockReturnDataWithDelay();
   } catch (e) {
     return reportErrorAndThrow(e);
   }
@@ -21,19 +30,20 @@ async function enableObservability(provisioningUrl) {
 // Provisioning API spec: https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/provisioning-api/pkg/provisioningapi/routes.go#L37
 async function isObservabilityEnabled(provisioningUrl) {
   try {
-    const { data } = await axios.get(provisioningUrl, { withCredentials: true });
+    // const { data } = await axios.get(provisioningUrl, { withCredentials: true });
+    const data = { xstatus: 'ready' };
     if (data && data.status) {
       // we currently ignore the 'status' payload and just check if the request was successful
       // We might improve this as part of https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2315
-      return true;
+      return mockReturnDataWithDelay(true);
     }
+    return false;
   } catch (e) {
     if (e.response.status === 404) {
       return false;
     }
     return reportErrorAndThrow(e);
   }
-  return reportErrorAndThrow(new Error('Failed to check provisioning')); // eslint-disable-line @gitlab/require-i18n-strings
 }
 
 async function fetchTrace(tracingUrl, traceId) {
@@ -42,18 +52,19 @@ async function fetchTrace(tracingUrl, traceId) {
       throw new Error('traceId is required.');
     }
 
-    const { data } = await axios.get(tracingUrl, {
-      withCredentials: true,
-      params: {
-        trace_id: traceId,
-      },
-    });
+    // const { data } = await axios.get(tracingUrl, {
+    //   withCredentials: true,
+    //   params: {
+    //     trace_id: traceId,
+    //   },
+    // });
+    const data = { traces: [mockData.traces.find((t) => t.trace_id === traceId)] };
 
     if (!Array.isArray(data.traces) || data.traces.length === 0) {
       throw new Error('traces are missing/invalid in the response'); // eslint-disable-line @gitlab/require-i18n-strings
     }
 
-    return data.traces[0];
+    return mockReturnDataWithDelay(data.traces[0]);
   } catch (e) {
     return reportErrorAndThrow(e);
   }
@@ -176,14 +187,15 @@ async function fetchTraces(tracingUrl, { filters = {}, pageToken, pageSize } = {
   }
 
   try {
-    const { data } = await axios.get(tracingUrl, {
-      withCredentials: true,
-      params,
-    });
+    // const { data } = await axios.get(tracingUrl, {
+    //   withCredentials: true,
+    //   params,
+    // });
+    const data = mockData;
     if (!Array.isArray(data.traces)) {
       throw new Error('traces are missing/invalid in the response'); // eslint-disable-line @gitlab/require-i18n-strings
     }
-    return data;
+    return mockReturnDataWithDelay(data);
   } catch (e) {
     return reportErrorAndThrow(e);
   }
@@ -191,15 +203,20 @@ async function fetchTraces(tracingUrl, { filters = {}, pageToken, pageSize } = {
 
 async function fetchServices(servicesUrl) {
   try {
-    const { data } = await axios.get(servicesUrl, {
-      withCredentials: true,
-    });
+    // const { data } = await axios.get(servicesUrl, {
+    //   withCredentials: true,
+    // });
+
+    const uniqueServices = new Set(
+      mockData.traces.map((t) => t.spans.map((s) => s.service_name)).flat(),
+    );
+    const data = { services: Array.from(uniqueServices).map((s) => ({ name: s })) };
 
     if (!Array.isArray(data.services)) {
       throw new Error('failed to fetch services. invalid response'); // eslint-disable-line @gitlab/require-i18n-strings
     }
 
-    return data.services;
+    return mockReturnDataWithDelay(data.services);
   } catch (e) {
     return reportErrorAndThrow(e);
   }
@@ -214,15 +231,24 @@ async function fetchOperations(operationsUrl, serviceName) {
       throw new Error('fetchOperations() - operationsUrl must contain $SERVICE_NAME$');
     }
     const url = operationsUrl.replace('$SERVICE_NAME$', serviceName);
-    const { data } = await axios.get(url, {
-      withCredentials: true,
-    });
+    // const { data } = await axios.get(url, {
+    //   withCredentials: true,
+    // });
+
+    console.log('fetching operations suggestions for', url); // eslint-disable-line @gitlab/require-i18n-strings
+    const uniqOps = new Set(
+      mockData.traces
+        .map((t) => t.spans.filter((s) => s.service_name === serviceName))
+        .flat()
+        .map((s) => s.operation),
+    );
+    const data = { operations: Array.from(uniqOps).map((s) => ({ name: s })) };
 
     if (!Array.isArray(data.operations)) {
       throw new Error('failed to fetch operations. invalid response'); // eslint-disable-line @gitlab/require-i18n-strings
     }
 
-    return data.operations;
+    return mockReturnDataWithDelay(data.operations);
   } catch (e) {
     return reportErrorAndThrow(e);
   }
diff --git a/app/assets/javascripts/observability/components/observability_container.vue b/app/assets/javascripts/observability/components/observability_container.vue
index 3027f01ea1e7..1d562d6f087b 100644
--- a/app/assets/javascripts/observability/components/observability_container.vue
+++ b/app/assets/javascripts/observability/components/observability_container.vue
@@ -41,12 +41,12 @@ export default {
 
     // TODO: Improve local GDK dev experience with tracing https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2308
     // Uncomment the lines below to to test this locally
-    // setTimeout(() => {
-    //   this.messageHandler({
-    //     data: { type: 'AUTH_COMPLETION', status: 'success' },
-    //     origin: new URL(this.oauthUrl).origin,
-    //   });
-    // }, 2000);
+    setTimeout(() => {
+      this.messageHandler({
+        data: { type: 'AUTH_COMPLETION', status: 'success' },
+        origin: new URL(this.oauthUrl).origin,
+      });
+    }, 2000);
   },
   destroyed() {
     window.removeEventListener('message', this.messageHandler);

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Daniele Rossetti

Merge request reports