From 7f337b695ed1d108fbab4a46228da9d1626253fb Mon Sep 17 00:00:00 2001 From: Feroze Mohideen Date: Mon, 9 Oct 2023 11:57:08 -0400 Subject: [PATCH] select logs by app id in v2 (#3760) --- .../handlers/porter_app/logs_apply_v2.go | 20 +++-- api/server/handlers/porter_app/stream_logs.go | 11 ++- api/server/router/porter_app.go | 4 +- dashboard/src/lib/hooks/useJobs.ts | 1 + .../home/app-dashboard/app-view/AppView.tsx | 1 + .../app-dashboard/app-view/tabs/LogsTab.tsx | 3 +- .../events/cards/AppEventCard.tsx | 4 +- .../focus-views/PredeployEventFocusView.tsx | 3 +- .../validate-apply/jobs/JobRunDetails.tsx | 1 + .../validate-apply/logs/Logs.tsx | 3 + .../validate-apply/logs/utils.ts | 6 +- dashboard/src/shared/api.tsx | 87 ++++++++----------- 12 files changed, 77 insertions(+), 67 deletions(-) diff --git a/api/server/handlers/porter_app/logs_apply_v2.go b/api/server/handlers/porter_app/logs_apply_v2.go index 88f79dfc4a..ccebf75d73 100644 --- a/api/server/handlers/porter_app/logs_apply_v2.go +++ b/api/server/handlers/porter_app/logs_apply_v2.go @@ -14,6 +14,7 @@ import ( "github.com/porter-dev/porter/api/server/shared" "github.com/porter-dev/porter/api/server/shared/apierrors" "github.com/porter-dev/porter/api/server/shared/config" + "github.com/porter-dev/porter/api/server/shared/requestutils" "github.com/porter-dev/porter/api/types" porter_agent "github.com/porter-dev/porter/internal/kubernetes/porter_agent/v2" "github.com/porter-dev/porter/internal/models" @@ -42,7 +43,7 @@ func NewAppLogsHandler( type AppLogsRequest struct { DeploymentTargetID string `schema:"deployment_target_id"` ServiceName string `schema:"service_name"` - AppName string `schema:"app_name"` + AppID uint `schema:"app_id"` Limit uint `schema:"limit"` StartRange time.Time `schema:"start_range,omitempty"` EndRange time.Time `schema:"end_range,omitempty"` @@ -53,6 +54,7 @@ type AppLogsRequest struct { const ( lokiLabel_PorterAppName = "porter_run_app_name" + lokiLabel_PorterAppID = "porter_run_app_id" lokiLabel_PorterServiceName = "porter_run_service_name" lokiLabel_PorterAppRevisionID = "porter_run_app_revision_id" lokiLabel_DeploymentTargetId = "porter_run_deployment_target_id" @@ -74,12 +76,19 @@ func (c *AppLogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - if request.AppName == "" { - err := telemetry.Error(ctx, span, nil, "must provide app name") + appName, reqErr := requestutils.GetURLParamString(r, types.URLParamPorterAppName) + if reqErr != nil { + err := telemetry.Error(ctx, span, reqErr, "porter app name not found in request") + c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) + return + } + telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "app-name", Value: appName}) + + if request.AppID == 0 { + err := telemetry.Error(ctx, span, nil, "must provide app id") c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) return } - telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "app-name", Value: request.AppName}) if request.ServiceName == "" { err := telemetry.Error(ctx, span, nil, "must provide service name") @@ -148,7 +157,8 @@ func (c *AppLogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { matchLabels := map[string]string{ lokiLabel_Namespace: namespace, - lokiLabel_PorterAppName: request.AppName, + lokiLabel_PorterAppName: appName, + lokiLabel_PorterAppID: fmt.Sprintf("%d", request.AppID), } if request.ServiceName != "all" { diff --git a/api/server/handlers/porter_app/stream_logs.go b/api/server/handlers/porter_app/stream_logs.go index 9ccf19887b..87eb604b75 100644 --- a/api/server/handlers/porter_app/stream_logs.go +++ b/api/server/handlers/porter_app/stream_logs.go @@ -16,6 +16,7 @@ import ( "github.com/porter-dev/porter/api/server/shared" "github.com/porter-dev/porter/api/server/shared/apierrors" "github.com/porter-dev/porter/api/server/shared/config" + "github.com/porter-dev/porter/api/server/shared/requestutils" "github.com/porter-dev/porter/api/server/shared/websocket" "github.com/porter-dev/porter/api/types" "github.com/porter-dev/porter/internal/models" @@ -54,12 +55,13 @@ func (c *StreamLogsLokiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request return } - if request.AppName == "" { - err := telemetry.Error(ctx, span, nil, "must provide app name") + appName, reqErr := requestutils.GetURLParamString(r, types.URLParamPorterAppName) + if reqErr != nil { + err := telemetry.Error(ctx, span, reqErr, "porter app name not found in request") c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) return } - telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "app-name", Value: request.AppName}) + telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "app-name", Value: appName}) if request.ServiceName == "" { err := telemetry.Error(ctx, span, nil, "must provide service name") @@ -126,8 +128,9 @@ func (c *StreamLogsLokiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request labels := []string{ fmt.Sprintf("%s=%s", lokiLabel_Namespace, namespace), - fmt.Sprintf("%s=%s", lokiLabel_PorterAppName, request.AppName), + fmt.Sprintf("%s=%s", lokiLabel_PorterAppName, appName), fmt.Sprintf("%s=%s", lokiLabel_DeploymentTargetId, request.DeploymentTargetID), + fmt.Sprintf("%s=%s", lokiLabel_PorterAppID, fmt.Sprintf("%d", request.AppID)), } if request.ServiceName != "all" { diff --git a/api/server/router/porter_app.go b/api/server/router/porter_app.go index 1df3cdfbbd..33758bd60a 100644 --- a/api/server/router/porter_app.go +++ b/api/server/router/porter_app.go @@ -891,7 +891,7 @@ func getPorterAppRoutes( Router: r, }) - // GET /api/projects/{project_id}/clusters/{cluster_id}/apps/logs -> cluster.NewAppLogsHandler + // GET /api/projects/{project_id}/clusters/{cluster_id}/apps/{porter_app_name}/logs -> cluster.NewAppLogsHandler appLogsEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, @@ -920,7 +920,7 @@ func getPorterAppRoutes( Router: r, }) - // GET /api/projects/{project_id}/clusters/{cluster_id}/apps/logs/loki -> namespace.NewStreamLogsLokiHandler + // GET /api/projects/{project_id}/clusters/{cluster_id}/apps/{porter_app_name}/logs/loki -> namespace.NewStreamLogsLokiHandler streamLogsLokiEndpoint := factory.NewAPIEndpoint( &types.APIRequestMetadata{ Verb: types.APIVerbGet, diff --git a/dashboard/src/lib/hooks/useJobs.ts b/dashboard/src/lib/hooks/useJobs.ts index 2f51524522..0b56bc19c2 100644 --- a/dashboard/src/lib/hooks/useJobs.ts +++ b/dashboard/src/lib/hooks/useJobs.ts @@ -10,6 +10,7 @@ const jobRunValidator = z.object({ labels: z.object({ "porter.run/app-revision-id": z.string(), "porter.run/service-name": z.string(), + "porter.run/app-id": z.string(), }), creationTimestamp: z.string(), uid: z.string(), diff --git a/dashboard/src/main/home/app-dashboard/app-view/AppView.tsx b/dashboard/src/main/home/app-dashboard/app-view/AppView.tsx index e21d853a86..6856f95a93 100644 --- a/dashboard/src/main/home/app-dashboard/app-view/AppView.tsx +++ b/dashboard/src/main/home/app-dashboard/app-view/AppView.tsx @@ -12,6 +12,7 @@ import AppHeader from "./AppHeader"; import { LatestRevisionProvider } from "./LatestRevisionContext"; export const porterAppValidator = z.object({ + id: z.number(), name: z.string(), git_branch: z.string().optional(), git_repo_id: z.number().optional(), diff --git a/dashboard/src/main/home/app-dashboard/app-view/tabs/LogsTab.tsx b/dashboard/src/main/home/app-dashboard/app-view/tabs/LogsTab.tsx index 2f3e490514..0fe143e8af 100644 --- a/dashboard/src/main/home/app-dashboard/app-view/tabs/LogsTab.tsx +++ b/dashboard/src/main/home/app-dashboard/app-view/tabs/LogsTab.tsx @@ -3,7 +3,7 @@ import Logs from "../../validate-apply/logs/Logs" import { useLatestRevision } from "../LatestRevisionContext"; const LogsTab: React.FC = () => { - const { projectId, clusterId, latestProto, deploymentTarget } = useLatestRevision(); + const { projectId, clusterId, latestProto, deploymentTarget, porterApp } = useLatestRevision(); const appName = latestProto.name const serviceNames = Object.keys(latestProto.services) @@ -16,6 +16,7 @@ const LogsTab: React.FC = () => { serviceNames={serviceNames} deploymentTargetId={deploymentTarget.id} filterPredeploy={true} + appId={porterApp.id} /> ); }; diff --git a/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/cards/AppEventCard.tsx b/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/cards/AppEventCard.tsx index 745997dead..379a29cb7a 100644 --- a/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/cards/AppEventCard.tsx +++ b/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/cards/AppEventCard.tsx @@ -36,7 +36,7 @@ const AppEventCard: React.FC = ({ event, deploymentTargetId, projectId, c { start_range: dayjs(event.created_at).subtract(1, 'minute').toISOString(), end_range: dayjs(event.updated_at).add(1, 'minute').toISOString(), - app_name: event.metadata.app_name, + app_id: event.porter_app_id, service_name: event.metadata.service_name, deployment_target_id: deploymentTargetId, limit: 1000, @@ -45,7 +45,7 @@ const AppEventCard: React.FC = ({ event, deploymentTargetId, projectId, c { project_id: projectId, cluster_id: clusterId, - app_name: appName, + porter_app_name: appName, } ) diff --git a/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/focus-views/PredeployEventFocusView.tsx b/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/focus-views/PredeployEventFocusView.tsx index 06e1f3ea8c..0be5e25bd6 100644 --- a/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/focus-views/PredeployEventFocusView.tsx +++ b/dashboard/src/main/home/app-dashboard/app-view/tabs/activity-feed/events/focus-views/PredeployEventFocusView.tsx @@ -19,7 +19,7 @@ type Props = { const PreDeployEventFocusView: React.FC = ({ event, }) => { - const { projectId, clusterId, latestProto, deploymentTarget } = useLatestRevision(); + const { projectId, clusterId, latestProto, deploymentTarget, porterApp } = useLatestRevision(); const appName = latestProto.name const serviceNames = [`${latestProto.name}-predeploy`] @@ -66,6 +66,7 @@ const PreDeployEventFocusView: React.FC = ({ deploymentTargetId={deploymentTarget.id} appRevisionId={event.metadata.app_revision_id} logFilterNames={["service_name"]} + appId={porterApp.id} /> ); diff --git a/dashboard/src/main/home/app-dashboard/validate-apply/jobs/JobRunDetails.tsx b/dashboard/src/main/home/app-dashboard/validate-apply/jobs/JobRunDetails.tsx index d2cbc9da75..7824c0f46d 100644 --- a/dashboard/src/main/home/app-dashboard/validate-apply/jobs/JobRunDetails.tsx +++ b/dashboard/src/main/home/app-dashboard/validate-apply/jobs/JobRunDetails.tsx @@ -74,6 +74,7 @@ const JobRunDetails: React.FC = ({ startTime: dayjs(jobRun.status.startTime ?? jobRun.metadata.creationTimestamp).subtract(30, 'second'), endTime: jobRun.status.completionTime != null ? dayjs(jobRun.status.completionTime).add(30, 'second') : undefined, }} + appId={parseInt(jobRun.metadata.labels["porter.run/app-id"])} /> ); diff --git a/dashboard/src/main/home/app-dashboard/validate-apply/logs/Logs.tsx b/dashboard/src/main/home/app-dashboard/validate-apply/logs/Logs.tsx index e4b303f1de..6fcb0eff87 100644 --- a/dashboard/src/main/home/app-dashboard/validate-apply/logs/Logs.tsx +++ b/dashboard/src/main/home/app-dashboard/validate-apply/logs/Logs.tsx @@ -42,6 +42,7 @@ type Props = { endTime?: Dayjs; }; filterPredeploy?: boolean; + appId: number; }; const Logs: React.FC = ({ @@ -54,6 +55,7 @@ const Logs: React.FC = ({ timeRange, logFilterNames = ["service_name", "revision", "output_stream"], filterPredeploy = false, + appId, }) => { const { search } = useLocation(); const queryParams = new URLSearchParams(search); @@ -194,6 +196,7 @@ const Logs: React.FC = ({ appRevisionId, filterPredeploy, timeRange, + appID: appId, }); useEffect(() => { diff --git a/dashboard/src/main/home/app-dashboard/validate-apply/logs/utils.ts b/dashboard/src/main/home/app-dashboard/validate-apply/logs/utils.ts index 54a21901c3..08e5e854dc 100644 --- a/dashboard/src/main/home/app-dashboard/validate-apply/logs/utils.ts +++ b/dashboard/src/main/home/app-dashboard/validate-apply/logs/utils.ts @@ -56,6 +56,7 @@ export const useLogs = ({ appRevisionId = "", timeRange, filterPredeploy, + appID, }: { projectID: number, clusterID: number, @@ -75,6 +76,7 @@ export const useLogs = ({ endTime?: Dayjs, }, filterPredeploy: boolean, + appID: number, } ) => { const [isLive, setIsLive] = useState(!setDate && (timeRange?.startTime == null && timeRange?.endTime == null)); @@ -180,11 +182,11 @@ export const useLogs = ({ const websocketBaseURL = `/api/projects/${projectID}/clusters/${clusterID}/apps/${appName}/logs/loki`; const searchParams = { - app_name: appName, service_name: serviceName, deployment_target_id: deploymentTargetId, search_param: searchParam, app_revision_id: appRevisionId, + app_id: appID.toString(), } const q = new URLSearchParams(searchParams).toString(); @@ -272,7 +274,7 @@ export const useLogs = ({ }> => { try { const getLogsReq = { - app_name: appName, + app_id: appID, service_name: serviceName, deployment_target_id: deploymentTargetId, search_param: searchParam, diff --git a/dashboard/src/shared/api.tsx b/dashboard/src/shared/api.tsx index 63a64806b6..4f399d644d 100644 --- a/dashboard/src/shared/api.tsx +++ b/dashboard/src/shared/api.tsx @@ -280,7 +280,7 @@ const getLogsWithinTimeRange = baseApi< const appLogs = baseApi< { - app_name: string; + app_id: number; service_name: string; deployment_target_id: string; limit: number; @@ -352,9 +352,8 @@ const getFeedEvents = baseApi< } >("GET", (pathParams) => { let { project_id, cluster_id, stack_name, page } = pathParams; - return `/api/projects/${project_id}/clusters/${cluster_id}/applications/${stack_name}/events?page=${ - page || 1 - }`; + return `/api/projects/${project_id}/clusters/${cluster_id}/applications/${stack_name}/events?page=${page || 1 + }`; }); const createEnvironment = baseApi< @@ -779,11 +778,9 @@ const detectBuildpack = baseApi< branch: string; } >("GET", (pathParams) => { - return `/api/projects/${pathParams.project_id}/gitrepos/${ - pathParams.git_repo_id - }/repos/${pathParams.kind}/${pathParams.owner}/${ - pathParams.name - }/${encodeURIComponent(pathParams.branch)}/buildpack/detect`; + return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id + }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name + }/${encodeURIComponent(pathParams.branch)}/buildpack/detect`; }); const detectGitlabBuildpack = baseApi< @@ -814,11 +811,9 @@ const getBranchContents = baseApi< branch: string; } >("GET", (pathParams) => { - return `/api/projects/${pathParams.project_id}/gitrepos/${ - pathParams.git_repo_id - }/repos/${pathParams.kind}/${pathParams.owner}/${ - pathParams.name - }/${encodeURIComponent(pathParams.branch)}/contents`; + return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id + }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name + }/${encodeURIComponent(pathParams.branch)}/contents`; }); const getProcfileContents = baseApi< @@ -834,11 +829,9 @@ const getProcfileContents = baseApi< branch: string; } >("GET", (pathParams) => { - return `/api/projects/${pathParams.project_id}/gitrepos/${ - pathParams.git_repo_id - }/repos/${pathParams.kind}/${pathParams.owner}/${ - pathParams.name - }/${encodeURIComponent(pathParams.branch)}/procfile`; + return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id + }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name + }/${encodeURIComponent(pathParams.branch)}/procfile`; }); const getPorterYamlContents = baseApi< @@ -854,11 +847,9 @@ const getPorterYamlContents = baseApi< branch: string; } >("GET", (pathParams) => { - return `/api/projects/${pathParams.project_id}/gitrepos/${ - pathParams.git_repo_id - }/repos/${pathParams.kind}/${pathParams.owner}/${ - pathParams.name - }/${encodeURIComponent(pathParams.branch)}/porteryaml`; + return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id + }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name + }/${encodeURIComponent(pathParams.branch)}/porteryaml`; }); const parsePorterYaml = baseApi< @@ -895,11 +886,9 @@ const getBranchHead = baseApi< branch: string; } >("GET", (pathParams) => { - return `/api/projects/${pathParams.project_id}/gitrepos/${ - pathParams.git_repo_id - }/repos/${pathParams.kind}/${pathParams.owner}/${ - pathParams.name - }/${encodeURIComponent(pathParams.branch)}/head`; + return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id + }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name + }/${encodeURIComponent(pathParams.branch)}/head`; }); const validatePorterApp = baseApi< @@ -925,21 +914,21 @@ const validatePorterApp = baseApi< const createApp = baseApi< | { - name: string; - type: "github"; - git_repo_id: number; - git_branch: string; - git_repo_name: string; - porter_yaml_path: string; - } + name: string; + type: "github"; + git_repo_id: number; + git_branch: string; + git_repo_name: string; + porter_yaml_path: string; + } | { - name: string; - type: "docker-registry"; - image: { - repository: string; - tag: string; - }; - }, + name: string; + type: "docker-registry"; + image: { + repository: string; + tag: string; + }; + }, { project_id: number; cluster_id: number; @@ -1070,7 +1059,7 @@ const getAppTemplate = baseApi< cluster_id: number; porter_app_name: string; }>("GET", ({ project_id, cluster_id, porter_app_name }) => { - return `/api/projects/${project_id}/clusters/${cluster_id}/apps/${porter_app_name}/templates`; + return `/api/projects/${project_id}/clusters/${cluster_id}/apps/${porter_app_name}/templates`; }) const getGitlabProcfileContents = baseApi< @@ -1977,11 +1966,9 @@ const getEnvGroup = baseApi< version?: number; } >("GET", (pathParams) => { - return `/api/projects/${pathParams.id}/clusters/${ - pathParams.cluster_id - }/namespaces/${pathParams.namespace}/envgroup?name=${pathParams.name}${ - pathParams.version ? "&version=" + pathParams.version : "" - }`; + return `/api/projects/${pathParams.id}/clusters/${pathParams.cluster_id + }/namespaces/${pathParams.namespace}/envgroup?name=${pathParams.name}${pathParams.version ? "&version=" + pathParams.version : "" + }`; }); const getConfigMap = baseApi< @@ -3039,7 +3026,7 @@ const removeStackEnvGroup = baseApi< `/api/v1/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/stacks/${stack_id}/remove_env_group/${env_group_name}` ); -const getGithubStatus = baseApi<{}, {}>("GET", ({}) => `/api/status/github`); +const getGithubStatus = baseApi<{}, {}>("GET", ({ }) => `/api/status/github`); const createSecretAndOpenGitHubPullRequest = baseApi< {