Skip to content

Commit

Permalink
Fix #84, #90. Enable Azure Streaming logs for Web and Function Apps
Browse files Browse the repository at this point in the history
- Enable Azure Logs Streaming from Azure Web App, Function App and Deployment Slots instances
- Add Azure Streaming Logs icons for tool window and actions in Azure Explorer nodes
- Update Logs Streaming actions logic to filter redundant actions (show "Start Streaming" action when streming is off and "Stop Streaming" action when streaming is started)
- Refactor Function App node to use WebAppBaseNode class to properly handle node actions on a Plugin side and remove redundant Rider Function App code
- Add static set of applications that has streaming logs enabled to be able to restore it when refreshing nodes or when application is restaed. Update Azure Streaming logs logic to set thee static map when logs streaming is started/stopped for a specific web, function app or deployment slot
  • Loading branch information
sdubov committed Aug 6, 2020
1 parent 9b6d6f7 commit 28493f6
Show file tree
Hide file tree
Showing 26 changed files with 189 additions and 390 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
anchor="bottom"
factoryClass="com.microsoft.intellij.helpers.StreamingLogsToolWindowFactory"
id="Azure Streaming Log"
icon="/icons/toolWindowAzureStreamingLog.svg"
canCloseContents="true"/>

<fileTypeFactory implementation="com.microsoft.intellij.language.arm.file.ARMFileTypeFactory"/>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 JetBrains s.r.o.
* Copyright (c) 2018-2020 JetBrains s.r.o.
* <p/>
* All rights reserved.
* <p/>
Expand All @@ -23,12 +23,16 @@
package com.microsoft.intellij.serviceexplorer

import com.google.common.collect.ImmutableList
import com.microsoft.intellij.serviceexplorer.azure.appservice.StartStreamingLogsAction
import com.microsoft.intellij.serviceexplorer.azure.appservice.StopStreamingLogsAction
import com.microsoft.intellij.serviceexplorer.azure.database.actions.*
import com.microsoft.tooling.msservices.serviceexplorer.Node
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionListener
import com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp.FunctionAppNode
import com.microsoft.tooling.msservices.serviceexplorer.azure.database.AzureDatabaseModule
import com.microsoft.tooling.msservices.serviceexplorer.azure.database.sqldatabase.SqlDatabaseNode
import com.microsoft.tooling.msservices.serviceexplorer.azure.database.sqlserver.SqlServerNode
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.WebAppNode
import java.util.*

class RiderNodeActionsMap : NodeActionsMap() {
Expand Down Expand Up @@ -57,6 +61,16 @@ class RiderNodeActionsMap : NodeActionsMap() {
.add(SqlDatabaseAddCurrentIpAddressToFirewallAction::class.java)
.add(SqlDatabaseConnectDataSourceAction::class.java)
.build()

node2Actions[WebAppNode::class.java] = ImmutableList.Builder<Class<out NodeActionListener>>()
.add(StartStreamingLogsAction::class.java)
.add(StopStreamingLogsAction::class.java)
.build()

node2Actions[FunctionAppNode::class.java] = ImmutableList.Builder<Class<out NodeActionListener>>()
.add(StartStreamingLogsAction::class.java)
.add(StopStreamingLogsAction::class.java)
.build()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.project.Project;
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.base.WebAppBaseStreamingLogs;
import org.jetbrains.annotations.NotNull;
import rx.Observable;
import rx.Subscription;
Expand Down Expand Up @@ -81,5 +82,6 @@ public void dispose() {
super.dispose();
this.isDisposed = true;
closeStreamingLog();
WebAppBaseStreamingLogs.INSTANCE.clearStartedStreamingLogMap();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) Microsoft Corporation
* Copyright (c) 2020 JetBrains s.r.o.
*
* All rights reserved.
*
Expand Down Expand Up @@ -34,6 +35,7 @@
import com.microsoft.intellij.util.PluginUtil;
import com.microsoft.tooling.msservices.components.DefaultLoader;
import com.microsoft.tooling.msservices.helpers.azure.sdk.AzureSDKManager;
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.base.WebAppBaseStreamingLogs;
import org.apache.commons.lang3.StringUtils;
import rx.Observable;

Expand Down Expand Up @@ -81,6 +83,7 @@ public void closeStreamingLog(Project project, String appId) {
DefaultLoader.getIdeHelper().runInBackground(project, CLOSING_STREAMING_LOG, false, true, null, () -> {
if (consoleViewMap.containsKey(appId) && consoleViewMap.get(appId).isActive()) {
consoleViewMap.get(appId).closeStreamingLog();
WebAppBaseStreamingLogs.INSTANCE.setStreamingLogsStarted(appId, false);
} else {
DefaultLoader.getIdeHelper().invokeLater(() -> PluginUtil.displayErrorDialog(
FAILED_TO_CLOSE_STREAMING_LOG, STREAMING_LOG_NOT_STARTED));
Expand Down Expand Up @@ -114,6 +117,7 @@ private void showAppServiceStreamingLog(Project project, String resourceId, ILog
return;
}
consoleView.startStreamingLog(log);
WebAppBaseStreamingLogs.INSTANCE.setStreamingLogsStarted(resourceId, true);
}
StreamingLogsToolWindowManager.getInstance().showStreamingLogConsole(
project, resourceId, logStreaming.getTitle(), consoleView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
public class StreamingLogsToolWindowFactory implements ToolWindowFactory {
@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
toolWindow.setIcon(
PluginUtil.getIcon(IconPathBuilder.custom(CommonConst.CosmosServerlessToolWindowIconName).build()));
// Set static icon in platformPlugin.xml instead to avoid showing/hiding icon when IDE is just started.
// toolWindow.setIcon(
// PluginUtil.getIcon(IconPathBuilder.custom(CommonConst.CosmosServerlessToolWindowIconName).build()));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) Microsoft Corporation
* Copyright (c) 2020 JetBrains s.r.o.
*
* All rights reserved.
*
Expand Down Expand Up @@ -27,12 +28,14 @@
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.microsoft.azuretools.azurecommons.helpers.AzureCmdException;
import com.microsoft.azuretools.azurecommons.helpers.Nullable;
import com.microsoft.azuretools.telemetrywrapper.EventUtil;
import com.microsoft.intellij.helpers.AppServiceStreamingLogManager;
import com.microsoft.tooling.msservices.components.DefaultLoader;
import com.microsoft.tooling.msservices.helpers.Name;
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionEvent;
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionListener;
import com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp.FunctionAppNode;
import com.microsoft.tooling.msservices.serviceexplorer.azure.function.FunctionNode;
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.WebAppNode;
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.deploymentslot.DeploymentSlotNode;
Expand Down Expand Up @@ -72,6 +75,14 @@ public StartStreamingLogsAction(FunctionNode functionNode) {
this.operation = START_STREAMING_LOG_FUNCTION_APP;
}

public StartStreamingLogsAction(FunctionAppNode functionNode) {
super();
this.project = (Project) functionNode.getProject();
this.resourceId = functionNode.getId();
this.service = FUNCTION;
this.operation = START_STREAMING_LOG_FUNCTION_APP;
}

@Override
protected void actionPerformed(NodeActionEvent nodeActionEvent) throws AzureCmdException {
EventUtil.executeWithLog(service, operation, op -> {
Expand All @@ -97,4 +108,9 @@ public void run(@NotNull ProgressIndicator progressIndicator) {
});
});
}

@Override
protected @Nullable String getIconPath() {
return "StartStreamingLog.svg";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) Microsoft Corporation
* Copyright (c) 2020 JetBrains s.r.o.
*
* All rights reserved.
*
Expand All @@ -24,12 +25,14 @@

import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.microsoft.azuretools.azurecommons.helpers.Nullable;
import com.microsoft.azuretools.telemetrywrapper.EventUtil;
import com.microsoft.intellij.helpers.AppServiceStreamingLogManager;
import com.microsoft.intellij.ui.util.UIUtils;
import com.microsoft.tooling.msservices.helpers.Name;
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionEvent;
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionListener;
import com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp.FunctionAppNode;
import com.microsoft.tooling.msservices.serviceexplorer.azure.function.FunctionNode;
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.WebAppNode;
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.deploymentslot.DeploymentSlotNode;
Expand Down Expand Up @@ -68,6 +71,14 @@ public StopStreamingLogsAction(FunctionNode functionNode) {
this.operation = STOP_STREAMING_LOG_FUNCTION_APP;
}

public StopStreamingLogsAction(FunctionAppNode functionNode) {
super();
this.project = (Project) functionNode.getProject();
this.resourceId = functionNode.getId();
this.service = FUNCTION;
this.operation = STOP_STREAMING_LOG_FUNCTION_APP;
}

@Override
protected void actionPerformed(NodeActionEvent nodeActionEvent) {
EventUtil.executeWithLog(service, operation,
Expand All @@ -76,4 +87,9 @@ protected void actionPerformed(NodeActionEvent nodeActionEvent) {
},
(err) -> UIUtils.showNotification(project, err.getMessage(), MessageType.ERROR));
}

@Override
protected @Nullable String getIconPath() {
return "StopStreamingLog.svg";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 JetBrains s.r.o.
* Copyright (c) 2019-2020 JetBrains s.r.o.
* <p/>
* All rights reserved.
* <p/>
Expand All @@ -25,10 +25,10 @@ package com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functi
import com.microsoft.azuretools.utils.AzureUIRefreshCore
import com.microsoft.azuretools.utils.AzureUIRefreshEvent
import com.microsoft.azuretools.utils.AzureUIRefreshListener
import com.microsoft.tooling.msservices.serviceexplorer.AzureRefreshableNode
import com.microsoft.tooling.msservices.serviceexplorer.Node
import com.microsoft.tooling.msservices.serviceexplorer.RefreshableNode

class AzureFunctionAppModule(parent: Node) : RefreshableNode(MODULE_ID, BASE_MODULE_NAME, parent, ICON_PATH) {
class AzureFunctionAppModule(parent: Node) : AzureRefreshableNode(MODULE_ID, BASE_MODULE_NAME, parent, ICON_PATH) {

companion object {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 JetBrains s.r.o.
* Copyright (c) 2019-2020 JetBrains s.r.o.
* <p/>
* All rights reserved.
* <p/>
Expand All @@ -23,6 +23,7 @@
package com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp

import com.microsoft.azuretools.core.mvp.model.functionapp.AzureFunctionAppMvpModel
import com.microsoft.azuretools.core.mvp.model.webapp.AzureWebAppMvpModel
import com.microsoft.azuretools.core.mvp.ui.base.MvpPresenter

class AzureFunctionAppModulePresenter : MvpPresenter<AzureFunctionAppModule>() {
Expand All @@ -32,14 +33,17 @@ class AzureFunctionAppModulePresenter : MvpPresenter<AzureFunctionAppModule>() {

val azureFunctionsList = AzureFunctionAppMvpModel.listAllFunctionApps(true)

for (functionApp in azureFunctionsList) {
val subscriptionId = functionApp.subscriptionId
val appId = functionApp.resource.id()
val appName = functionApp.resource.name()
val state = functionApp.resource.state()
val hostName = functionApp.resource.defaultHostName()
for (functionAppResource in azureFunctionsList) {
val subscriptionId = functionAppResource.subscriptionId
val functionApp = functionAppResource.resource
val appId = functionApp.id()
val appName = functionApp.name()
val state = functionApp.state()
val hostName = functionApp.defaultHostName()
val os = functionApp.operatingSystem().name

mvpView.addChildNode(FunctionAppNode(mvpView, subscriptionId, appId, appName, state, hostName))
mvpView.addChildNode(
FunctionAppNode(mvpView, subscriptionId, appId, appName, state, hostName, os))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,27 @@ package com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functi
import com.microsoft.azure.CommonIcons
import com.microsoft.azuretools.core.mvp.model.functionapp.AzureFunctionAppMvpModel
import com.microsoft.tooling.msservices.components.DefaultLoader
import com.microsoft.tooling.msservices.serviceexplorer.*
import com.microsoft.tooling.msservices.serviceexplorer.NodeAction
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionEvent
import com.microsoft.tooling.msservices.serviceexplorer.NodeActionListener
import com.microsoft.tooling.msservices.serviceexplorer.azure.AzureNodeActionPromptListener
import com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp.base.FunctionAppBaseNodeView
import com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp.base.FunctionAppState
import com.microsoft.tooling.msservices.serviceexplorer.azure.appservice.functionapp.functions.FunctionNode
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.base.WebAppBaseNode
import com.microsoft.tooling.msservices.serviceexplorer.azure.webapp.base.WebAppBaseState
import java.util.logging.Logger

class FunctionAppNode(parent: AzureFunctionAppModule,
override val subscriptionId: String,
override val functionAppId: String,
override val functionAppName: String,
override var state: String,
private val hostName: String) :
RefreshableNode(functionAppId, functionAppName, parent, getFunctionAppIcon(state), true),
FunctionAppVirtualInterface,
FunctionAppBaseNodeView {
subscriptionId: String,
val functionAppId: String,
val functionAppName: String,
state: String,
hostName: String,
os: String)
: WebAppBaseNode(functionAppId, functionAppName, FUNCTION_LABEL, parent, subscriptionId, hostName, os, state) {

companion object {
private const val FUNCTION_LABEL = "Function"

private const val ACTION_START = "Start"
private const val ACTION_STOP = "Stop"
private const val ACTION_RESTART = "Restart"
Expand All @@ -56,10 +59,6 @@ class FunctionAppNode(parent: AzureFunctionAppModule,

private const val ICON_FUNCTION_APP_RUNNING = "FunctionAppRunning.svg"
private const val ICON_FUNCTION_APP_STOPPED = "FunctionAppStopped.svg"

private fun getFunctionAppIcon(state: String) =
if (FunctionAppState.fromString(state) == FunctionAppState.RUNNING) ICON_FUNCTION_APP_RUNNING
else ICON_FUNCTION_APP_STOPPED
}

private val logger = Logger.getLogger(FunctionAppNode::class.java.name)
Expand All @@ -81,6 +80,10 @@ class FunctionAppNode(parent: AzureFunctionAppModule,
presenter.onAttachView(this@FunctionAppNode)
}

override fun getIcon(os: String?, label: String?, state: WebAppBaseState?): String =
if (state == WebAppBaseState.STOPPED) ICON_FUNCTION_APP_STOPPED
else ICON_FUNCTION_APP_RUNNING

override fun onError(message: String) {
}

Expand All @@ -107,21 +110,21 @@ class FunctionAppNode(parent: AzureFunctionAppModule,
}
}

override fun renderNode(state: FunctionAppState) {
when (state) {
FunctionAppState.RUNNING -> {
this.state = state.name
override fun renderNode(nodeState: WebAppBaseState) {
when (nodeState) {
WebAppBaseState.RUNNING -> {
state = nodeState
setIconPath(ICON_FUNCTION_APP_RUNNING)
}
FunctionAppState.STOPPED -> {
this.state = state.name
WebAppBaseState.STOPPED -> {
state = nodeState
setIconPath(ICON_FUNCTION_APP_STOPPED)
}
}
}

override fun getNodeActions(): MutableList<NodeAction> {
val isRunning = FunctionAppState.fromString(state) == FunctionAppState.RUNNING
val isRunning = state == WebAppBaseState.RUNNING

val stopAction = getNodeActionByName(ACTION_STOP)
val startAction = getNodeActionByName(ACTION_START)
Expand Down
Loading

0 comments on commit 28493f6

Please sign in to comment.