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

Preview pane telemetry #1299

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
Binary file modified src/common/Telemetry/PowerToys.wprp
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Include="MarkdownPreviewHandlerControl.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MarkdownTelemetry.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using System.Xml.Linq;
using Common;
using Markdig;
using Markdig.Helpers;
using MarkdownPreviewHandler.Properties;

namespace MarkdownPreviewHandler
Expand Down Expand Up @@ -55,7 +54,7 @@ public class MarkdownPreviewHandlerControl : FormHandlerControl
/// <summary>
/// True if external image is blocked, false otherwise.
/// </summary>
private bool imagesBlocked = false;
private bool infoBarDisplayed = false;

/// <summary>
/// Initializes a new instance of the <see cref="MarkdownPreviewHandlerControl"/> class.
Expand All @@ -75,47 +74,51 @@ public override void DoPreview<T>(T dataSource)
{
this.InvokeOnControlThread(() =>
{
this.imagesBlocked = false;
try
{
this.infoBarDisplayed = false;

StringBuilder sb = new StringBuilder();
string filePath = dataSource as string;
string fileText = File.ReadAllText(filePath);
this.extension.BaseUrl = Path.GetDirectoryName(filePath);
StringBuilder sb = new StringBuilder();
string filePath = dataSource as string;
string fileText = File.ReadAllText(filePath);
this.extension.BaseUrl = Path.GetDirectoryName(filePath);

MarkdownPipeline pipeline = this.pipelineBuilder.Build();
string parsedMarkdown = Markdown.ToHtml(fileText, pipeline);
sb.AppendFormat("{0}{1}{2}", this.htmlHeader, parsedMarkdown, this.htmlFooter);
string markdownHTML = this.RemoveScriptFromHTML(sb.ToString());
MarkdownPipeline pipeline = this.pipelineBuilder.Build();
string parsedMarkdown = Markdown.ToHtml(fileText, pipeline);
sb.AppendFormat("{0}{1}{2}", this.htmlHeader, parsedMarkdown, this.htmlFooter);
string markdownHTML = this.RemoveScriptFromHTML(sb.ToString());

this.browser = new WebBrowser
{
DocumentText = markdownHTML,
Dock = DockStyle.Fill,
IsWebBrowserContextMenuEnabled = false,
ScriptErrorsSuppressed = true,
ScrollBarsEnabled = true,
};
this.browser.Navigating += this.WebBrowserNavigating;
this.Controls.Add(this.browser);

if (this.imagesBlocked)
{
this.infoBar = new RichTextBox
this.browser = new WebBrowser
{
Text = Resources.BlockedImageInfoText,
BackColor = Color.LightYellow,
Multiline = true,
Dock = DockStyle.Top,
ReadOnly = true,
DocumentText = markdownHTML,
Dock = DockStyle.Fill,
IsWebBrowserContextMenuEnabled = false,
ScriptErrorsSuppressed = true,
ScrollBarsEnabled = true,
};
this.infoBar.ContentsResized += this.RTBContentsResized;
this.infoBar.ScrollBars = RichTextBoxScrollBars.None;
this.infoBar.BorderStyle = BorderStyle.None;
this.browser.Navigating += this.WebBrowserNavigating;
this.Controls.Add(this.browser);

if (this.infoBarDisplayed)
{
this.infoBar = this.GetTextBoxControl(Resources.BlockedImageInfoText);
this.Controls.Add(this.infoBar);
}

this.Resize += this.FormResized;
base.DoPreview(dataSource);
MarkdownTelemetry.Log.MarkdownFilePreviewed();
}
catch (Exception e)
{
MarkdownTelemetry.Log.MarkdownFilePreviewError(e.Message);
this.infoBarDisplayed = true;
this.infoBar = this.GetTextBoxControl(Resources.MarkdownNotPreviewedError);
this.Resize += this.FormResized;
this.Controls.Clear();
this.Controls.Add(this.infoBar);
base.DoPreview(dataSource);
}

this.Resize += this.FormResized;
base.DoPreview(dataSource);
});
}

Expand All @@ -139,6 +142,28 @@ public string RemoveScriptFromHTML(string html)
return doc.ToString();
}

/// <summary>
/// Gets a textbox control.
/// </summary>
/// <param name="message">Message to be displayed in textbox.</param>
/// <returns>An object of type <see cref="RichTextBox"/>.</returns>
private RichTextBox GetTextBoxControl(string message)
{
RichTextBox richTextBox = new RichTextBox
{
Text = message,
BackColor = Color.LightYellow,
Multiline = true,
Dock = DockStyle.Top,
ReadOnly = true,
};
richTextBox.ContentsResized += this.RTBContentsResized;
richTextBox.ScrollBars = RichTextBoxScrollBars.None;
richTextBox.BorderStyle = BorderStyle.None;

return richTextBox;
}

/// <summary>
/// Callback when RichTextBox is resized.
/// </summary>
Expand All @@ -157,7 +182,7 @@ private void RTBContentsResized(object sender, ContentsResizedEventArgs e)
/// <param name="e">Provides data for the event.</param>
private void FormResized(object sender, EventArgs e)
{
if (this.imagesBlocked)
if (this.infoBarDisplayed)
{
this.infoBar.Width = this.Width;
}
Expand All @@ -168,7 +193,7 @@ private void FormResized(object sender, EventArgs e)
/// </summary>
private void ImagesBlockedCallBack()
{
this.imagesBlocked = true;
this.infoBarDisplayed = true;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics.Tracing;
using PreviewHandlerCommon.Telemetry;

namespace MarkdownPreviewHandler
{
/// <summary>
/// Telemetry helper class for markdown renderer.
/// </summary>
public class MarkdownTelemetry : TelemetryBase
{
/// <summary>
/// Name for ETW event.
/// </summary>
private const string EventSourceName = "Microsoft.PowerToys";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe this could be in the base :) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible that same projects can have multiple event sources. That's why it's better to initialize them from the derived classes.


/// <summary>
/// ETW event name when markdown is previewed.
/// </summary>
private const string MarkdownFilePreviewedEventName = "PowerPreview_MDRenderer_Previewed";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks making the changes! Looks good to me. Do you think we can make the similar change to the settings.cpp file (NOT require since it is out of the scope of the PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am more inclined of putting it in a separate PR. This PR is focused on C# telemetry.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good!!!


/// <summary>
/// ETW event name when error is thrown during markdown preview.
/// </summary>
private const string MarkdownFilePreviewErrorEventName = "PowerPreview_MDRenderer_Error";

/// <summary>
/// Initializes a new instance of the <see cref="MarkdownTelemetry"/> class.
/// </summary>
public MarkdownTelemetry()
: base(EventSourceName)
{
return;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes!

}

/// <summary>
/// Gets an instance of the <see cref="MarkdownTelemetry"/> class.
/// </summary>
public static MarkdownTelemetry Log { get; } = new MarkdownTelemetry();

/// <summary>
/// Publishes ETW event when markdown is previewed successfully.
/// </summary>
public void MarkdownFilePreviewed()
{
this.Write(MarkdownFilePreviewedEventName, new EventSourceOptions()
{
Keywords = ProjectKeywordMeasure,
Tags = ProjectTelemetryTagProductAndServicePerformance,
});
}

/// <summary>
/// Publishes ETW event when markdown could not be previewed.
/// </summary>
public void MarkdownFilePreviewError(string message)
{
this.Write(
MarkdownFilePreviewErrorEventName,
new EventSourceOptions()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't seem to be changing, perhaps we can store it as a global variable somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! I will update this.

{
Keywords = ProjectKeywordMeasure,
Tags = ProjectTelemetryTagProductAndServicePerformance,
},
new { Message = message, });
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,8 @@
<value>Some pictures have been blocked to help prevent the sender from identifying this computer. Open this item to view pictures.</value>
<comment>This text is displayed if image is blocked from being displayed.</comment>
</data>
<data name="MarkdownNotPreviewedError" xml:space="preserve">
<value>The markdown could not be preview due to an internal error.</value>
<comment>This text is displayed if markdown fails to preview</comment>
</data>
</root>
1 change: 1 addition & 0 deletions src/modules/previewpane/common/PreviewHandlerCommon.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="handlers\StreamBasedPreviewHandler.cs" />
<Compile Include="examplehandler\TestCustomHandler.cs" />
<Compile Include="Telemetry\TelemetryBase.cs" />
<Compile Include="Utilities\StreamWrapper.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
44 changes: 44 additions & 0 deletions src/modules/previewpane/common/Telemetry/TelemetryBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics.Eventing.Reader;
using System.Diagnostics.Tracing;

namespace PreviewHandlerCommon.Telemetry
{
/// <summary>
/// Base class for telemetry events.
/// </summary>
public class TelemetryBase : EventSource
{
/// <summary>
/// The event tag for this event source.
/// </summary>
public const EventTags ProjectTelemetryTagProductAndServicePerformance = (EventTags)0x0u;

/// <summary>
/// The event keyword for this event source.
/// </summary>
public const EventKeywords ProjectKeywordMeasure = (EventKeywords)0x0;

/// <summary>
/// Group ID for Powertoys project.
/// </summary>
private static readonly string[] PowerToysTelemetryTraits = { "ETW_GROUP", "{42749043-438c-46a2-82be-c6cbeb192ff2}" };

/// <summary>
/// Initializes a new instance of the <see cref="TelemetryBase"/> class.
/// </summary>
/// <param name="eventSourceName">.</param>
public TelemetryBase(
string eventSourceName)
: base(
eventSourceName,
EventSourceSettings.EtwSelfDescribingEventFormat,
PowerToysTelemetryTraits)
{
return;
}
}
}