Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show run file application logs #286

Merged
merged 7 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
"title": "%vscode-dapr.applications.stop-app.title%",
"category": "Dapr"
},
{
"command": "vscode-dapr.applications.view-app-logs",
"title": "%vscode-dapr.applications.view-app-logs.title%",
"category": "Dapr"
},
{
"command": "vscode-dapr.applications.view-dapr-logs",
"title": "%vscode-dapr.applications.view-dapr-logs.title%",
"category": "Dapr"
},
{
"command": "vscode-dapr.help.getStarted",
"title": "%vscode-dapr.help.getStarted.title%",
Expand Down Expand Up @@ -184,6 +194,14 @@
"command": "vscode-dapr.applications.debug",
"when": "never"
},
{
"command": "vscode-dapr.applications.view-app-logs",
"when": "never"
},
{
"command": "vscode-dapr.applications.view-dapr-logs",
"when": "never"
},
{
"command": "vscode-dapr.runs.debug",
"when": "never"
Expand Down Expand Up @@ -229,6 +247,16 @@
"when": "view == vscode-dapr.views.applications && viewItem =~ /application/",
"group": "stop"
},
{
"command": "vscode-dapr.applications.view-app-logs",
"when": "view == vscode-dapr.views.applications && viewItem =~ /application/ && viewItem =~ /hasLogs/",
"group": "logs"
},
{
"command": "vscode-dapr.applications.view-dapr-logs",
"when": "view == vscode-dapr.views.applications && viewItem =~ /application/ && viewItem =~ /hasLogs/",
"group": "logs"
},
{
"command": "vscode-dapr.runs.debug",
"when": "view == vscode-dapr.views.applications && viewItem =~ /run/ && viewItem =~ /attachable/",
Expand Down
2 changes: 2 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"vscode-dapr.applications.publish-message.title": "Publish Message to Application",
"vscode-dapr.applications.publish-all-message.title": "Publish Message to All Applications",
"vscode-dapr.applications.stop-app.title": "Stop Application",
"vscode-dapr.applications.view-app-logs.title": "View Application Logs",
"vscode-dapr.applications.view-dapr-logs.title": "View Dapr Logs",

"vscode-dapr.configuration.paths.daprPath.description": "The full path to the dapr binary.",
"vscode-dapr.configuration.paths.daprdPath.description": "The full path to the daprd binary.",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/applications/debugApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export async function debugApplication(application: DaprApplication): Promise<vo

const createDebugApplicationCommand = () => (context: IActionContext, node: DaprApplicationNode | undefined): Promise<void> => {
if (node == undefined) {
throw new Error(localize('commands.applications.debugApplication.noPaletteSupport', 'Debugging requires selecting an application in the Dapr view.'));
throw new Error(localize('commands.applications.viewLogs.noPaletteSupport', 'Debugging requires selecting an application in the Dapr view.'));
}

return debugApplication(node.application);
Expand Down
20 changes: 20 additions & 0 deletions src/commands/applications/viewAppLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as nls from 'vscode-nls';
import DaprApplicationNode from "../../views/applications/daprApplicationNode";
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { getLocalizationPathForFile } from '../../util/localization';
import { viewLogs } from './viewLogs';

const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename));

const createViewAppLogsCommand = () => (context: IActionContext, node: DaprApplicationNode | undefined): Promise<void> => {
if (node == undefined) {
throw new Error(localize('commands.applications.viewAppLogs.noPaletteSupport', 'Viewing application logs requires selecting an application in the Dapr view.'));
}

return viewLogs(node.application, 'app');
}

export default createViewAppLogsCommand;
20 changes: 20 additions & 0 deletions src/commands/applications/viewDaprLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as nls from 'vscode-nls';
import DaprApplicationNode from "../../views/applications/daprApplicationNode";
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { getLocalizationPathForFile } from '../../util/localization';
import { viewLogs } from "./viewLogs";

const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename));

const createViewDaprLogsCommand = () => (context: IActionContext, node: DaprApplicationNode | undefined): Promise<void> => {
if (node == undefined) {
throw new Error(localize('commands.applications.viewDaprLogs.noPaletteSupport', 'Viewing Dapr logs requires selecting an application in the Dapr view.'));
}

return viewLogs(node.application, 'daprd');
}

export default createViewDaprLogsCommand;
47 changes: 47 additions & 0 deletions src/commands/applications/viewLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as nls from 'vscode-nls';
import * as path from 'path';
import * as vscode from 'vscode';
import { getLocalizationPathForFile } from '../../util/localization';
import { DaprApplication } from "../../services/daprApplicationProvider";
import { fromRunFilePath, getAppId } from "../../util/runFileReader";

const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename));

export type DaprLogType = 'app' | 'daprd';

export async function viewLogs(application: DaprApplication, type: DaprLogType): Promise<void> {
if (!application.runTemplatePath) {
throw new Error(localize('commands.applications.viewLogs.noRunFile', 'Logs can be viewed only when applications are started via a run file.'));
}

const runFile = await fromRunFilePath(vscode.Uri.file(application.runTemplatePath));

const runFileApplication = (runFile.apps ?? []).find(app => application.appId === getAppId(app));

if (!runFileApplication) {
throw new Error(localize('commands.applications.viewLogs.appNotFound', 'The application \'{0}\' was not found in the run file \'{1}\'.', application.appId, application.runTemplatePath));
}

if (!runFileApplication.appDirPath) {
throw new Error(localize('commands.applications.viewLogs.appDirNotFound', 'The directory for application \'{0}\' was not found in the run file \'{1}\'.', application.appId, application.runTemplatePath));
}

const runFileDirectory = path.dirname(application.runTemplatePath);
const appDirectory = path.join(runFileDirectory, runFileApplication.appDirPath, '.dapr', 'logs');

const pattern = `${application.appId}_${type}_*.log`;
const relativePattern = new vscode.RelativePattern(appDirectory, pattern);

const files = await vscode.workspace.findFiles(relativePattern);

if (files.length === 0) {
throw new Error(localize('commands.applications.viewLogs.logNotFound', 'No logs for application \'{0}\' were found.', application.appId));
}

const newestFile = files.reduce((newestFile, nextFile) => newestFile.fsPath.localeCompare(nextFile.fsPath) < 0 ? nextFile : newestFile);

await vscode.window.showTextDocument(newestFile);
}
30 changes: 2 additions & 28 deletions src/debug/daprDebugConfigurationProvider.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as fs from 'fs/promises';
import * as nls from 'vscode-nls';
import * as path from 'path';
import * as vscode from 'vscode';
import { load } from 'js-yaml';
import { getLocalizationPathForFile } from '../util/localization';
import { DaprApplication, DaprApplicationProvider } from '../services/daprApplicationProvider';
import { filter, first, firstValueFrom, map, race, timeout } from 'rxjs';
import { debugApplication } from '../commands/applications/debugApplication';
import { UserInput } from '../services/userInput';
import { withAggregateTokens } from '../util/aggregateCancellationTokenSource';
import { fromCancellationToken } from '../util/observableCancellationToken';
import { fromRunFilePath, getAppId } from '../util/runFileReader';

const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename));

Expand All @@ -22,36 +20,12 @@ export interface DaprDebugConfiguration extends vscode.DebugConfiguration {
runFile: string;
}

interface DaprRunApplication {
appDirPath?: string;
appID?: string;
}

interface DaprRunFile {
apps?: DaprRunApplication[];
}

function getAppId(app: DaprRunApplication): string {
if (app.appID) {
return app.appID;
}

if (app.appDirPath) {
return path.basename(app.appDirPath);
}

throw new Error(localize('debug.daprDebugConfigurationProvider.unableToDetermineAppId', 'Unable to determine a configured application\'s ID.'));
}

async function getAppIdsToDebug(configuration: DaprDebugConfiguration): Promise<Set<string>> {
if (configuration.includeApps) {
return new Set<string>(configuration.includeApps);
}

const runFileContent = await fs.readFile(configuration.runFile, { encoding: 'utf8' });

// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const runFile = load(runFileContent) as DaprRunFile;
const runFile = await fromRunFilePath(vscode.Uri.file(configuration.runFile));

const appIds = new Set<string>();

Expand Down
4 changes: 4 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { AsyncDisposable } from './util/asyncDisposable';
import createStartRunCommand from './commands/applications/startRun';
import createStopRunCommand from './commands/applications/stopRun';
import { DaprDebugConfigurationProvider } from './debug/daprDebugConfigurationProvider';
import createViewAppLogsCommand from './commands/applications/viewAppLogs';
import createViewDaprLogsCommand from './commands/applications/viewDaprLogs';

interface ExtensionPackage {
engines: { [key: string]: string };
Expand Down Expand Up @@ -102,6 +104,8 @@ export function activate(context: vscode.ExtensionContext): Promise<void> {
telemetryProvider.registerCommandWithTelemetry('vscode-dapr.applications.publish-all-message', createPublishAllMessageCommand(daprApplicationProvider, daprClient, ext.outputChannel, ui, context.workspaceState));
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.publish-message', createPublishMessageCommand(daprApplicationProvider, daprClient, ext.outputChannel, ui, context.workspaceState));
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.stop-app', createStopCommand(daprCliClient, ui));
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.view-app-logs', createViewAppLogsCommand());
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.view-dapr-logs', createViewDaprLogsCommand());
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.help.readDocumentation', createReadDocumentationCommand(ui));
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.help.getStarted', createGetStartedCommand(ui));
telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.help.installDapr', createInstallDaprCommand(ui));
Expand Down
48 changes: 48 additions & 0 deletions src/util/runFileReader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as nls from 'vscode-nls';
import * as path from 'path';
import * as vscode from 'vscode';
import { getLocalizationPathForFile } from '../util/localization';
import { load } from "js-yaml";

const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename));

export interface DaprRunApplication {
appDirPath?: string;
appID?: string;
}

export interface DaprRunFile {
apps?: DaprRunApplication[];
}

export async function fromRunFilePath(path: vscode.Uri): Promise<DaprRunFile>{
const runFileContent = await vscode.workspace.fs.readFile(path);

if (!runFileContent) {
throw new Error(localize('util.runFileReader.noContent', 'There is no run file content at path: {0}', path.fsPath));
}

return fromRunFileContent(runFileContent.toString());
}

export function fromRunFileContent(content: string): DaprRunFile {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const runFile = load(content) as DaprRunFile;

return runFile;
}

export function getAppId(app: DaprRunApplication): string {
if (app.appID) {
return app.appID;
}

if (app.appDirPath) {
return path.basename(app.appDirPath);
}

throw new Error(localize('util.runFileReader.unableToDetermineAppId', 'Unable to determine a configured application\'s ID.'));
}
6 changes: 5 additions & 1 deletion src/views/applications/daprApplicationNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ export default class DaprApplicationNode implements TreeNode {
getTreeItem(): Promise<vscode.TreeItem> {
const item = new vscode.TreeItem(this.application.appId, vscode.TreeItemCollapsibleState.Collapsed);

item.contextValue = ['application', this.application.appPid !== undefined ? 'attachable' : ''].join(' ');
item.contextValue = [
'application',
this.application.appPid !== undefined ? 'attachable' : '',
this.application.runTemplatePath ? 'hasLogs' : ''
].join(' ');
item.iconPath = new vscode.ThemeIcon(this.application.appPid !== undefined ? 'server-process' : 'browser');

return Promise.resolve(item);
Expand Down