diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-08-23 08:44:31 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-08-23 08:44:31 +0300 |
| commit | 02ae577faa0bd4938507061d603e4f9447e2b64f (patch) | |
| tree | 7daf0e275338ec92e93bfca39f2d529d93858162 /Software | |
| parent | 67770063ff1a1c5c522e3bc29f442c42eb6dc521 (diff) | |
| download | Tango-02ae577faa0bd4938507061d603e4f9447e2b64f.tar.gz Tango-02ae577faa0bd4938507061d603e4f9447e2b64f.zip | |
Fixed issue with insights file datetime utc.
added insights application exception/crash.
added remote actions service.
fixed issue with LiteDB hang on application start/exit.
reduced insights listener empty frames.
Diffstat (limited to 'Software')
35 files changed, 578 insertions, 89 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/app_crash.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/app_crash.png Binary files differnew file mode 100644 index 000000000..303952d86 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/app_crash.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/app_exception.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/app_exception.png Binary files differnew file mode 100644 index 000000000..d14bb84af --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/app_exception.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/bug_report.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/bug_report.png Binary files differnew file mode 100644 index 000000000..05d00014d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Images/bug_report.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj index ea6616985..617ca2d99 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj @@ -312,6 +312,13 @@ <ItemGroup> <Resource Include="Images\detection.png" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\app_crash.png" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\bug_report.png" /> + <Resource Include="Images\app_exception.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml index 5426ba4ea..b4b3fe746 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml @@ -11,7 +11,7 @@ <DataTemplate x:Key="InsightEventTemplate" DataType="{x:Type commonInsights:InsightsReadyEvent}"> - <Border Tag="{Binding DataContext,RelativeSource={RelativeSource AncestorType=views:InsightsView}}" Padding="10 5" Cursor="Hand" IsHitTestVisible="True" BorderThickness="1" CornerRadius="3" BorderBrush="{StaticResource FSE_PrimaryBackgroundLightBrush}"> + <Border Tag="{Binding DataContext,RelativeSource={RelativeSource AncestorType=views:InsightsView}}" Padding="10 5" IsHitTestVisible="True" BorderThickness="1" CornerRadius="3" BorderBrush="{StaticResource FSE_PrimaryBackgroundLightBrush}"> <Border.ToolTip> <StackPanel> <TextBlock TextWrapping="Wrap"> @@ -139,7 +139,7 @@ </DataTemplate> <DataTemplate x:Key="InsightBugTemplate" DataType="{x:Type commonInsights:InsightsReadyBug}"> - <Border MaxWidth="300" Tag="{Binding DataContext,RelativeSource={RelativeSource AncestorType=views:InsightsView}}" Padding="10 5" Cursor="Hand" IsHitTestVisible="True" BorderThickness="1" CornerRadius="15" BorderBrush="{StaticResource FSE_ErrorBrush}"> + <Border MaxWidth="300" Tag="{Binding DataContext,RelativeSource={RelativeSource AncestorType=views:InsightsView}}"> <Border.ToolTip> <StackPanel> <TextBlock TextWrapping="Wrap"> @@ -167,7 +167,7 @@ </Border.ToolTip> <Border.Style> <Style TargetType="Border"> - <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundDarkBrush}"></Setter> + <Setter Property="Opacity" Value="1"></Setter> <Setter Property="ContextMenu"> <Setter.Value> <ContextMenu> @@ -192,7 +192,7 @@ </Setter> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> - <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + <Setter Property="Opacity" Value="0.8"></Setter> </Trigger> <EventTrigger RoutedEvent="PreviewMouseRightButtonUp"> <EventTrigger.Actions> @@ -208,10 +208,140 @@ </Style.Triggers> </Style> </Border.Style> - <DockPanel> - <material:PackIcon Height="16" Width="16" Kind="Ladybug" Foreground="{StaticResource FSE_ErrorBrush}" VerticalAlignment="Center"/> - <TextBlock TextTrimming="CharacterEllipsis" VerticalAlignment="Center" Margin="5 0 0 0" Text="{Binding Bug.Title,Mode=OneWay}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"></TextBlock> - </DockPanel> + <StackPanel> + <Image Source="../Images/bug_report.png" Stretch="Uniform" HorizontalAlignment="Center" RenderOptions.BitmapScalingMode="Fant" Width="48" /> + <TextBlock Foreground="{StaticResource FSE_ErrorBrush}" FontWeight="SemiBold">Bug Report</TextBlock> + </StackPanel> + </Border> + </DataTemplate> + + <DataTemplate x:Key="InsightApplicationExceptionTemplate" DataType="{x:Type commonInsights:InsightsReadyApplicationException}"> + <Border Tag="{Binding DataContext,RelativeSource={RelativeSource AncestorType=views:InsightsView}}" IsHitTestVisible="True" Canvas.ZIndex="200"> + <Border.ToolTip> + <StackPanel> + <TextBlock>Unhandled Application Exception</TextBlock> + <TextBlock> + <Run>Time:</Run> + <Run Text="{Binding Time,Converter={StaticResource DateTimeUtcToLocalDateTime},StringFormat='MM/dd/yyyy hh:mm:ss'}"></Run> + </TextBlock> + <StackPanel Margin="0 5 0 0"> + <TextBlock Foreground="{StaticResource FSE_ErrorBrush}">Exception</TextBlock> + <Rectangle Margin="0 2 0 0" HorizontalAlignment="Stretch" VerticalAlignment="Top" StrokeThickness="1" Stroke="{StaticResource FSE_PrimaryForegroundBrush}" StrokeDashArray="5" /> + <TextBlock Text="{Binding Exception,Mode=OneWay}" MaxHeight="200" TextWrapping="Wrap" MaxWidth="400" Margin="0 5 0 0"></TextBlock> + </StackPanel> + </StackPanel> + </Border.ToolTip> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Opacity" Value="1"></Setter> + <Setter Property="ContextMenu"> + <Setter.Value> + <ContextMenu> + <MenuItem ToolTip="View extended details about this exception" Header="View Details" Command="{Binding PlacementTarget.Tag.ViewApplicationExceptionCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Chip" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem ToolTip="Locate related application logs using the Application module" Header="Peek Application Logs" Command="{Binding PlacementTarget.Tag.PeekApplicationLogsCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Application" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem ToolTip="Locate related firmware logs using the Firmware module" Header="Peek Firmware Logs" Command="{Binding PlacementTarget.Tag.PeekFirmwareLogsCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Chip" /> + </MenuItem.Icon> + </MenuItem> + </ContextMenu> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Opacity" Value="0.8"></Setter> + </Trigger> + <EventTrigger RoutedEvent="PreviewMouseRightButtonUp"> + <EventTrigger.Actions> + <BeginStoryboard> + <Storyboard> + <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen"> + <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/> + </BooleanAnimationUsingKeyFrames> + </Storyboard> + </BeginStoryboard> + </EventTrigger.Actions> + </EventTrigger> + </Style.Triggers> + </Style> + </Border.Style> + <StackPanel> + <Image Source="../Images/app_exception.png" Stretch="Uniform" HorizontalAlignment="Center" RenderOptions.BitmapScalingMode="Fant" Width="48" /> + <TextBlock Foreground="{StaticResource FSE_ErrorBrush}" FontWeight="SemiBold">Application Exception</TextBlock> + </StackPanel> + </Border> + </DataTemplate> + + <DataTemplate x:Key="InsightApplicationCrashTemplate" DataType="{x:Type commonInsights:InsightsReadyApplicationException}"> + <Border Tag="{Binding DataContext,RelativeSource={RelativeSource AncestorType=views:InsightsView}}" IsHitTestVisible="True" Margin="-80 0 0 0"> + <Border.ToolTip> + <StackPanel> + <TextBlock>Application Crash!</TextBlock> + <TextBlock> + <Run>Time:</Run> + <Run Text="{Binding Time,Converter={StaticResource DateTimeUtcToLocalDateTime},StringFormat='MM/dd/yyyy hh:mm:ss'}"></Run> + </TextBlock> + <StackPanel Margin="0 5 0 0"> + <TextBlock Text="{Binding Exception,Mode=OneWay}" TextWrapping="Wrap" MaxHeight="200" MaxWidth="400" Margin="0 5 0 0" TextTrimming="CharacterEllipsis"></TextBlock> + </StackPanel> + </StackPanel> + </Border.ToolTip> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Opacity" Value="1"></Setter> + <Setter Property="ContextMenu"> + <Setter.Value> + <ContextMenu> + <MenuItem ToolTip="View extended details about this exception" Header="View Details" Command="{Binding PlacementTarget.Tag.ViewApplicationExceptionCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Chip" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem ToolTip="Locate related application logs using the Application module" Header="Peek Application Logs" Command="{Binding PlacementTarget.Tag.PeekApplicationLogsCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Application" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem ToolTip="Locate related firmware logs using the Firmware module" Header="Peek Firmware Logs" Command="{Binding PlacementTarget.Tag.PeekFirmwareLogsCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Chip" /> + </MenuItem.Icon> + </MenuItem> + </ContextMenu> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Opacity" Value="0.8"></Setter> + </Trigger> + <EventTrigger RoutedEvent="PreviewMouseRightButtonUp"> + <EventTrigger.Actions> + <BeginStoryboard> + <Storyboard> + <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen"> + <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/> + </BooleanAnimationUsingKeyFrames> + </Storyboard> + </BeginStoryboard> + </EventTrigger.Actions> + </EventTrigger> + </Style.Triggers> + </Style> + </Border.Style> + <Grid> + <Image Source="../Images/app_crash.png" Stretch="Fill" RenderOptions.BitmapScalingMode="Fant" Width="160" Height="40" /> + <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Red" FontWeight="SemiBold" FontSize="{StaticResource FSE_SmallFontSize}">Application Crash!</TextBlock> + </Grid> </Border> </DataTemplate> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs index 6ef92e525..ccbb77cf1 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs @@ -20,6 +20,7 @@ using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Commands; using Tango.FSE.Common; +using Tango.FSE.Common.Dialogs; using Tango.FSE.Common.Insights; using Tango.FSE.Insights.Contracts; using Tango.FSE.Insights.Dialogs; @@ -189,6 +190,8 @@ namespace Tango.FSE.Insights.ViewModels public RelayCommand<InsightsReadyBug> OpenBugReportCommand { get; set; } + public RelayCommand<InsightsReadyApplicationException> ViewApplicationExceptionCommand { get; set; } + public RelayCommand AnalyzeCommand { get; set; } #endregion @@ -210,6 +213,7 @@ namespace Tango.FSE.Insights.ViewModels PeekApplicationLogsCommand = new RelayCommand<InsightReadyBase>(PeekAnnotationApplicationLogs); PeekFirmwareLogsCommand = new RelayCommand<InsightReadyBase>(PeekAnnotationFirmwareLogs); OpenBugReportCommand = new RelayCommand<InsightsReadyBug>(OpenAnnotationBugReport); + ViewApplicationExceptionCommand = new RelayCommand<InsightsReadyApplicationException>(ViewAnnotationApplicationException); AnalyzeCommand = new RelayCommand(Analyze, () => InsightsPackage != null); } @@ -482,12 +486,12 @@ namespace Tango.FSE.Insights.ViewModels line.Stroke = connected ? Brushes.Green : Brushes.DarkGray; line.X1 = date; line.X2 = date; - line.ShowLabel = false; - line.AnnotationLabels.Add(new AnnotationLabel() - { - LabelPlacement = connected ? LabelPlacement.TopRight : LabelPlacement.BottomLeft, - Text = connected ? "machine connected" : "machine disconnected" - }); + //line.ShowLabel = false; + //line.AnnotationLabels.Add(new AnnotationLabel() + //{ + // LabelPlacement = connected ? LabelPlacement.TopRight : LabelPlacement.BottomLeft, + // Text = connected ? "machine connected" : "machine disconnected" + //}); Annotations.Add(line); } @@ -495,7 +499,7 @@ namespace Tango.FSE.Insights.ViewModels { var y = 0.05; - foreach (var insight in package.Events.Cast<InsightReadyBase>().Concat(package.Statuses).Concat(package.Bugs).OrderBy(x => x.Time)) + foreach (var insight in package.Events.Cast<InsightReadyBase>().Concat(package.Statuses).Concat(package.Bugs).Concat(package.ApplicationExceptions).OrderBy(x => x.Time)) { CustomAnnotation annotation = new CustomAnnotation(); annotation.X1 = insight.Time.ToLocalTime(); @@ -509,14 +513,30 @@ namespace Tango.FSE.Insights.ViewModels } else if (insight is InsightsReadyStatus status) { + Panel.SetZIndex(annotation, 1); annotation.Content = status; annotation.ContentTemplate = Application.Current.Resources["InsightStatusTemplate"] as DataTemplate; } else if (insight is InsightsReadyBug bug) { + Panel.SetZIndex(annotation, 2); annotation.Content = bug; annotation.ContentTemplate = Application.Current.Resources["InsightBugTemplate"] as DataTemplate; } + else if (insight is InsightsReadyApplicationException appException) + { + annotation.Content = appException; + Panel.SetZIndex(annotation, 3); + + if (appException.IsApplicationCrash) + { + annotation.ContentTemplate = Application.Current.Resources["InsightApplicationCrashTemplate"] as DataTemplate; + } + else + { + annotation.ContentTemplate = Application.Current.Resources["InsightApplicationExceptionTemplate"] as DataTemplate; + } + } Annotations.Add(annotation); @@ -531,7 +551,7 @@ namespace Tango.FSE.Insights.ViewModels #endregion - #region Logs Peeking + #region Menu Items Handling private async void PeekAnnotationFirmwareLogs(InsightReadyBase ev) { @@ -551,15 +571,20 @@ namespace Tango.FSE.Insights.ViewModels } } - #endregion - - #region Bug Report - private void OpenAnnotationBugReport(InsightsReadyBug bug) { Process.Start(bug.Bug.URL); } + private async void ViewAnnotationApplicationException(InsightsReadyApplicationException appException) + { + MessageLogItem logItem = new MessageLogItem(); + logItem.Category = LogCategory.Critical; + logItem.TimeStamp = appException.Time; + logItem.Message = appException.Exception; + await NotificationProvider.ShowDialog(new ApplicationLogItemViewVM() { LogItem = logItem }); + } + #endregion #region Event Handlers diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs index 3f57a50d9..a823295a9 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs @@ -14,6 +14,7 @@ namespace Tango.FSE.Common.Insights public List<InsightsReadyFrame> Frames { get; set; } public List<InsightsReadyEvent> Events { get; set; } public List<InsightsReadyStatus> Statuses { get; set; } + public List<InsightsReadyApplicationException> ApplicationExceptions { get; set; } public List<InsightsReadyBug> Bugs { get; set; } public InsightsPackage() @@ -22,6 +23,7 @@ namespace Tango.FSE.Common.Insights Events = new List<InsightsReadyEvent>(); Statuses = new List<InsightsReadyStatus>(); Bugs = new List<InsightsReadyBug>(); + ApplicationExceptions = new List<InsightsReadyApplicationException>(); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyApplicationException.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyApplicationException.cs new file mode 100644 index 000000000..9f4524100 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyApplicationException.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.Insights +{ + public class InsightsReadyApplicationException : InsightReadyBase + { + public String Exception { get; set; } + public bool IsApplicationCrash { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteActions/IRemoteActionsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteActions/IRemoteActionsProvider.cs new file mode 100644 index 000000000..024a8ac39 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteActions/IRemoteActionsProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.RemoteActions +{ + public interface IRemoteActionsProvider + { + void SimulateApplicationException(bool causeCrash); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index b89d30f82..cbd70e665 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -228,6 +228,7 @@ <Compile Include="INotifyApplicationReady.cs" /> <Compile Include="Insights\InsightReadyBase.cs" /> <Compile Include="Insights\IInsightsProvider.cs" /> + <Compile Include="Insights\InsightsReadyApplicationException.cs" /> <Compile Include="Insights\InsightsReadyBug.cs" /> <Compile Include="Insights\InsightsReadyEvent.cs" /> <Compile Include="Insights\InsightsHandler.cs" /> @@ -262,6 +263,7 @@ <Compile Include="Performance\PerformancePackageEventArgs.cs" /> <Compile Include="MachineUpdates\IMachineUpdatesProvider.cs" /> <Compile Include="MachineUpdates\MachineUpdatesResult.cs" /> + <Compile Include="RemoteActions\IRemoteActionsProvider.cs" /> <Compile Include="RemoteDesktop\DesktopFrameReceivedEventArgs.cs" /> <Compile Include="RemoteDesktop\IRemoteDesktopProvider.cs" /> <Compile Include="RemoteDesktop\Mp4VideoEncoder.cs" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs index 5b17bd5e0..08120c24f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs @@ -55,7 +55,10 @@ namespace Tango.FSE.UI.Insights var response = await MachineProvider.MachineOperator.SendGenericRequest<InsightsRequest, InsightsResponse>(new InsightsRequest() { StartDateUTC = startDateUTC, - EndDateUTC = endTimeUTC + EndDateUTC = endTimeUTC, + IncludeStatuses = true, + IncludeEvents = true, + IncludeApplicationExceptions = true }, new TransportRequestConfig() { Timeout = TimeSpan.FromMinutes(1), @@ -142,6 +145,16 @@ namespace Tango.FSE.UI.Insights }); } + foreach (var appException in insightsFile.ApplicationExceptions) + { + package.ApplicationExceptions.Add(new InsightsReadyApplicationException() + { + Time = appException.Time, + Exception = appException.Exception, + IsApplicationCrash = appException.IsApplicationCrash + }); + } + if (AuthenticationProvider.CurrentUser.HasPermission(Permissions.FSE_ModifyBugReport)) { try diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteActions/DefaultRemoteActionsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteActions/DefaultRemoteActionsProvider.cs new file mode 100644 index 000000000..98256fa3c --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteActions/DefaultRemoteActionsProvider.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.RemoteActions; +using Tango.PPC.Shared.RemoteActions; + +namespace Tango.FSE.UI.RemoteActions +{ + public class DefaultRemoteActionsProvider : IRemoteActionsProvider + { + [TangoInject] + private IMachineProvider MachineProvider { get; set; } + + public void SimulateApplicationException(bool causeCrash) + { + var response = MachineProvider.MachineOperator.SendGenericRequest<SimulateApplicationExceptionRequest, SimulateApplicationExceptionResponse>(new SimulateApplicationExceptionRequest() + { + CrashApplication = causeCrash, + }).Result; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj index 8974407d4..17fa594fd 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj @@ -330,6 +330,7 @@ <Compile Include="Panes\MachineConnectionPaneVM.cs" /> <Compile Include="Performance\DefaultPerformanceProvider.cs" /> <Compile Include="MachineUpdates\DefaultMachineUpdatesProvider.cs" /> + <Compile Include="RemoteActions\DefaultRemoteActionsProvider.cs" /> <Compile Include="RemoteDesktop\DefaultRemoteDesktopProvider.cs" /> <Compile Include="RemoteUpgrade\DefaultRemoteUpgradeManager.cs" /> <Compile Include="Resolution\DefaultResolutionService.cs" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs index 5da32809f..e70b25d09 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs @@ -68,6 +68,8 @@ using Tango.FSE.Common.FileAssociation; using Tango.FSE.UI.FileAssociation; using Tango.FSE.Common.Insights; using Tango.FSE.UI.Insights; +using Tango.FSE.Common.RemoteActions; +using Tango.FSE.UI.RemoteActions; namespace Tango.FSE.UI { @@ -107,6 +109,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Unregister<IRemoteSqlProvider>(); TangoIOC.Default.Unregister<IFileAssociationProvider>(); TangoIOC.Default.Unregister<IInsightsProvider>(); + TangoIOC.Default.Unregister<IRemoteActionsProvider>(); //TangoIOC.Default.Unregister<ExternalBridgeScanner>(); //TangoIOC.Default.Unregister<IDiagnosticsFrameProvider>(); //TangoIOC.Default.Unregister<IEventLogger>(); @@ -146,6 +149,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Register<IRemoteSqlProvider, DefaultRemoteSqlProvider>(); TangoIOC.Default.Register<IFileAssociationProvider, DefaultFileAssociationProvider>(); TangoIOC.Default.Register<IInsightsProvider, DefaultInsightsProvider>(); + TangoIOC.Default.Register<IRemoteActionsProvider, DefaultRemoteActionsProvider>(); TangoIOC.Default.Register<MainWindowVM>(); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs index f015c3bad..75c5ae9cd 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs @@ -89,6 +89,11 @@ namespace Tango.PPC.Common.Insights insightsFile.Statuses = InsightsManager.Default.GetStatuses(request.StartDateUTC, request.EndDateUTC); } + if (request.IncludeApplicationExceptions) + { + insightsFile.ApplicationExceptions = InsightsManager.Default.GetApplicationExceptions(request.StartDateUTC, request.EndDateUTC); + } + insightsFile.ToFile(filePath); }); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs new file mode 100644 index 000000000..477663342 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.RemoteActions +{ + public interface IRemoteActionsService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj index 08e49621c..ed0c30755 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj @@ -179,6 +179,7 @@ <Compile Include="RemoteDesktop\RemoteDesktopClient.cs" /> <Compile Include="RemoteJob\DefaultRemoteJobService.cs" /> <Compile Include="RemoteJob\IRemoteJobService.cs" /> + <Compile Include="RemoteActions\IRemoteActionsService.cs" /> <Compile Include="SQL\DefaultRemoteSqlService.cs" /> <Compile Include="SQL\IRemoteSqlService.cs" /> <Compile Include="Synchronization\DefaultMachineDataSynchronizer.cs" /> @@ -483,7 +484,7 @@ </Target> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs index 6603a05b5..b34895e78 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs @@ -13,11 +13,13 @@ namespace Tango.PPC.Shared.Insights public bool IncludeEvents { get; set; } public bool IncludeStatuses { get; set; } + public bool IncludeApplicationExceptions { get; set; } public InsightsRequest() { IncludeEvents = true; IncludeStatuses = true; + IncludeApplicationExceptions = true; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs new file mode 100644 index 000000000..76216edad --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteActions +{ + public class SimulateApplicationExceptionRequest + { + public bool CrashApplication { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs new file mode 100644 index 000000000..e0b71ddf4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteActions +{ + public class SimulateApplicationExceptionResponse + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj index de1eb03b1..bfd4d587b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj @@ -95,6 +95,8 @@ <DependentUpon>Settings.settings</DependentUpon> <DesignTimeSharedInput>True</DesignTimeSharedInput> </Compile> + <Compile Include="RemoteActions\SimulateApplicationExceptionRequest.cs" /> + <Compile Include="RemoteActions\SimulateApplicationExceptionResponse.cs" /> <Compile Include="RemoteUpgrade\StartRemoteFirmwareUpgradeRequest.cs" /> <Compile Include="RemoteUpgrade\StartRemoteFirmwareUpgradeResponse.cs" /> <Compile Include="RemoteUpgrade\StartRemoteApplicationUpgradeResponse.cs" /> @@ -137,5 +139,8 @@ <Name>Tango.SystemInfo</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <Folder Include="Simulation\" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs index 16eb656a8..e478dba77 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs @@ -13,6 +13,7 @@ using Tango.BL; using Tango.Core; using Tango.Core.DI; using Tango.Core.Helpers; +using Tango.Insights; using Tango.Integration.Operation; using Tango.Logging; using Tango.PPC.Common; @@ -29,7 +30,7 @@ namespace Tango.PPC.UI /// </summary> public partial class App : Application { - private WpfGlobalExceptionTrapper exceptionTrapper; + public static WpfGlobalExceptionTrapper ExceptionTrapper; public static String[] StartupArgs { get; private set; } private LogManager LogManager = LogManager.Default; @@ -80,9 +81,9 @@ namespace Tango.PPC.UI base.OnStartup(e); - exceptionTrapper = new WpfGlobalExceptionTrapper(); - exceptionTrapper.Initialize(this); - exceptionTrapper.ApplicationCrashed += ExceptionTrapper_ApplicationCrashed; + ExceptionTrapper = new WpfGlobalExceptionTrapper(); + ExceptionTrapper.Initialize(this); + ExceptionTrapper.ApplicationCrashed += ExceptionTrapper_ApplicationCrashed; CoreSettings.DefaultDataSource = new DataSource() { @@ -100,10 +101,21 @@ namespace Tango.PPC.UI private async void GetLastApplicationCrashFromWindows() { - var logItem = await exceptionTrapper.GetLastApplicationCrashEventLog(); + var logItem = await ExceptionTrapper.GetLastApplicationCrashEventLog(60); if (logItem != null) { LogManager.Log(logItem); + + try + { + InsightsManager.Default.InsertApplicationException(new InsightsApplicationException() + { + Time = DateTime.UtcNow, + Exception = logItem.Message, + IsApplicationCrash = true + }); + } + catch { } } } @@ -135,6 +147,17 @@ namespace Tango.PPC.UI try { + InsightsManager.Default.InsertApplicationException(new InsightsApplicationException() + { + Time = DateTime.UtcNow, + Exception = e.Exception.ToString() + }); + } + catch + { } + + try + { if (Application.Current == null) { new Application { ShutdownMode = ShutdownMode.OnExplicitShutdown }; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs index 54193a793..29f4e65be 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs @@ -476,6 +476,7 @@ namespace Tango.PPC.UI.PPCApplication { var frame = InsightsFrame.CreateEmpty(DateTime.UtcNow); InsightsManager.Default.InsertFrame(frame); + InsightsManager.Default.Dispose(); } catch {} @@ -528,6 +529,7 @@ namespace Tango.PPC.UI.PPCApplication { var frame = InsightsFrame.CreateEmpty(DateTime.UtcNow); InsightsManager.Default.InsertFrame(frame); + InsightsManager.Default.Dispose(); } catch { } @@ -566,6 +568,7 @@ namespace Tango.PPC.UI.PPCApplication { var frame = InsightsFrame.CreateEmpty(DateTime.UtcNow); InsightsManager.Default.InsertFrame(frame); + InsightsManager.Default.Dispose(); } catch { } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs new file mode 100644 index 000000000..1b8780f91 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.Core.Threading; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Common.RemoteActions; +using Tango.PPC.Common.Threading; +using Tango.PPC.Shared.RemoteActions; + +namespace Tango.PPC.UI.RemoteActions +{ + [TangoCreateWhenRegistered] + public class DefaultRemoteActionsService : IRemoteActionsService, IExternalBridgeRequestHandler + { + [TangoInject] + private IDispatcherProvider DispatcherProvider { get; set; } + + public DefaultRemoteActionsService(IPPCExternalBridgeService externalBridge) + { + externalBridge.RegisterRequestHandler(this); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do nothing. + } + + [ExternalBridgeRequestHandlerMethod(typeof(SimulateApplicationExceptionRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnSimulateApplicationExceptionRequest(SimulateApplicationExceptionRequest request, String token, ExternalBridgeReceiver receiver) + { + await receiver.SendGenericResponse(new SimulateApplicationExceptionResponse(), token); + + Thread.Sleep(500); + + DispatcherProvider.Invoke(() => + { + if (request.CrashApplication) + { + App.ExceptionTrapper.Disable(); + throw new OutOfMemoryException("This is a simulated exception to cause the application to crash."); + } + else + { + throw new ApplicationException("This is a simulated exception to cause an unhandled application error."); + } + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj b/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj index 569621432..bfb16f10d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj @@ -181,6 +181,7 @@ <Compile Include="Notifications\PendingNotification.cs" /> <Compile Include="PPCApplication\DefaultPPCApplicationManager.cs" /> <Compile Include="Printing\DefaultPrintingManager.cs" /> + <Compile Include="RemoteActions\DefaultRemoteActionsService.cs" /> <Compile Include="Threading\DefaultDispatcherProvider.cs" /> <Compile Include="ViewModelLocator.cs" /> <Compile Include="ViewModels\EmergencyViewVM.cs" /> @@ -446,6 +447,9 @@ <Resource Include="Images\firmware.png" /> <Resource Include="Images\power_off_2.gif" /> <Resource Include="Images\loading_anim.gif" /> + <Content Include="..\..\Build\ColorLib\Debug\Tango.ColorLib_v4.dll"> + <Link>Tango.ColorLib_v4.dll</Link> + </Content> <Content Include="Manifests\release.xml" /> <Content Include="Manifests\debug.xml" /> <None Include="firmware_package.tfp"> @@ -717,7 +721,7 @@ if $(ConfigurationName) == Debug copy /Y "$(TargetDir)Packages" "$(TargetDir)"</ </PropertyGroup> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs index b5da9f066..7011cd3be 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs @@ -24,6 +24,7 @@ using Tango.PPC.Common.Notifications; using Tango.PPC.Common.OS; using Tango.PPC.Common.Performance; using Tango.PPC.Common.Printing; +using Tango.PPC.Common.RemoteActions; using Tango.PPC.Common.RemoteAssistance; using Tango.PPC.Common.RemoteDesktop; using Tango.PPC.Common.RemoteJob; @@ -42,6 +43,7 @@ using Tango.PPC.UI.Navigation; using Tango.PPC.UI.Notifications; using Tango.PPC.UI.PPCApplication; using Tango.PPC.UI.Printing; +using Tango.PPC.UI.RemoteActions; using Tango.PPC.UI.Threading; using Tango.PPC.UI.ViewModels; using Tango.PPC.UI.Views; @@ -94,6 +96,7 @@ namespace Tango.PPC.UI TangoIOC.Default.Unregister<IRemoteJobService>(); TangoIOC.Default.Unregister<IRemoteSqlService>(); TangoIOC.Default.Unregister<IInsightsService>(); + TangoIOC.Default.Unregister<IRemoteActionsService>(); if (App.StartupArgs != null && App.StartupArgs.Contains("-webDebug")) { @@ -135,6 +138,7 @@ namespace Tango.PPC.UI TangoIOC.Default.Register<IRemoteJobService, DefaultRemoteJobService>(); TangoIOC.Default.Register<IRemoteSqlService, DefaultRemoteSqlService>(); TangoIOC.Default.Register<IInsightsService, DefaultInsightsService>(); + TangoIOC.Default.Register<IRemoteActionsService, DefaultRemoteActionsService>(); TangoIOC.Default.Register<LoadingViewVM>(); TangoIOC.Default.Register<MainViewVM>(); diff --git a/Software/Visual_Studio/Tango.Core/Bson/BsonUtcSerializer.cs b/Software/Visual_Studio/Tango.Core/Bson/BsonUtcSerializer.cs new file mode 100644 index 000000000..6f5cb7700 --- /dev/null +++ b/Software/Visual_Studio/Tango.Core/Bson/BsonUtcSerializer.cs @@ -0,0 +1,68 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Core.Bson +{ + public class BsonUtcSerializer : JsonSerializer + { + private class DateTimeConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(DateTime) == objectType + || typeof(DateTime?) == objectType; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var dateTimeOffset = (DateTime)value; + // Serialize DateTimeOffset as round-trip formatted string + serializer.Serialize(writer, dateTimeOffset.ToString("O")); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Date) + return null; + + DateTime dt; + + var dateWithOffset = (String)reader.Value; + + if (String.IsNullOrEmpty(dateWithOffset)) + return null; + + if (DateTime.TryParseExact(dateWithOffset, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dt)) + return dt; + + return null; + } + + } + + private class DateTimeContractResolver : DefaultContractResolver + { + protected override JsonContract CreateContract(Type objectType) + { + var contract = base.CreateContract(objectType); + + if (objectType == typeof(DateTime) || objectType == typeof(DateTime?)) + contract.Converter = new DateTimeConverter(); + + return contract; + } + } + + public BsonUtcSerializer() + { + ContractResolver = new DateTimeContractResolver(); + DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; + } + } +} diff --git a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj index 2db9c8643..2ecd441f2 100644 --- a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj +++ b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj @@ -95,6 +95,7 @@ <Compile Include="..\Versioning\GlobalVersionInfo.cs"> <Link>GlobalVersionInfo.cs</Link> </Compile> + <Compile Include="Bson\BsonUtcSerializer.cs" /> <Compile Include="Components\CmdCommand.cs" /> <Compile Include="CustomAttributes\PropertyIndexAttribute.cs" /> <Compile Include="CustomAttributes\StringFormatAttribute.cs" /> @@ -216,7 +217,7 @@ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> <Import Project="..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets')" /> diff --git a/Software/Visual_Studio/Tango.Insights/InsightsApplicationException.cs b/Software/Visual_Studio/Tango.Insights/InsightsApplicationException.cs new file mode 100644 index 000000000..193412ae8 --- /dev/null +++ b/Software/Visual_Studio/Tango.Insights/InsightsApplicationException.cs @@ -0,0 +1,20 @@ +using LiteDB; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Insights +{ + public class InsightsApplicationException + { + [BsonId(true)] + [JsonIgnore] + public int Id { get; set; } + public DateTime Time { get; set; } + public String Exception { get; set; } + public bool IsApplicationCrash { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.Insights/InsightsFile.cs b/Software/Visual_Studio/Tango.Insights/InsightsFile.cs index 4eba06035..2bcb2f761 100644 --- a/Software/Visual_Studio/Tango.Insights/InsightsFile.cs +++ b/Software/Visual_Studio/Tango.Insights/InsightsFile.cs @@ -6,22 +6,33 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Core.Bson; namespace Tango.Insights { public class InsightsFile { + private static JsonSerializer _serializer; + + static InsightsFile() + { + _serializer = new BsonUtcSerializer(); + } + public List<InsightsFrame> Frames { get; set; } public List<InsightsEvent> Events { get; set; } public List<InsightsStatus> Statuses { get; set; } + public List<InsightsApplicationException> ApplicationExceptions { get; set; } + public InsightsFile() { Frames = new List<InsightsFrame>(); Events = new List<InsightsEvent>(); Statuses = new List<InsightsStatus>(); + ApplicationExceptions = new List<InsightsApplicationException>(); } public Stream ToStream() @@ -35,8 +46,7 @@ namespace Tango.Insights { using (BsonWriter writer = new BsonWriter(ms)) { - JsonSerializer serializer = new JsonSerializer(); - serializer.Serialize(writer, this); + _serializer.Serialize(writer, this); ms.Position = 0; return ms.ToArray(); } @@ -52,8 +62,7 @@ namespace Tango.Insights { using (BsonReader reader = new BsonReader(stream)) { - JsonSerializer serializer = new JsonSerializer(); - return serializer.Deserialize<InsightsFile>(reader); + return _serializer.Deserialize<InsightsFile>(reader); } } diff --git a/Software/Visual_Studio/Tango.Insights/InsightsListener.cs b/Software/Visual_Studio/Tango.Insights/InsightsListener.cs index 6a9e7726b..f57753cfc 100644 --- a/Software/Visual_Studio/Tango.Insights/InsightsListener.cs +++ b/Software/Visual_Studio/Tango.Insights/InsightsListener.cs @@ -25,6 +25,7 @@ namespace Tango.Insights private int _timerCount; private int _deleteTicks; private bool _writing; + private bool _emptyWritten; public bool IsStarted { get; private set; } public TimeSpan SamplingInterval { get; set; } @@ -164,16 +165,21 @@ namespace Tango.Insights queue.Clear(); frame = InsightsFrame.FromInsightsMonitors(monitorsAvg, DateTime.UtcNow.Subtract(SamplingInterval)); + _emptyWritten = false; + _manager.InsertFrame(frame); + Debug.WriteLine("Insights frame inserted."); } else { - frame = InsightsFrame.CreateEmpty(DateTime.UtcNow.Subtract(SamplingInterval)); + if (!_emptyWritten) + { + frame = InsightsFrame.CreateEmpty(DateTime.UtcNow.Subtract(SamplingInterval)); + _emptyWritten = true; + _manager.InsertFrame(frame); + Debug.WriteLine("Insights empty frame inserted."); + } } - _manager.InsertFrame(frame); - - Debug.WriteLine("Insights frame inserted."); - _timerCount++; if (_timerCount >= _deleteTicks) @@ -185,6 +191,9 @@ namespace Tango.Insights deleted = _manager.DeleteStatuses(maxDate); Debug.WriteLine($"{deleted} insights machine statuses deleted."); + + deleted = _manager.DeleteApplicationExceptions(maxDate); + Debug.WriteLine($"{deleted} insights application exceptions deleted."); } } catch (Exception ex) diff --git a/Software/Visual_Studio/Tango.Insights/InsightsManager.cs b/Software/Visual_Studio/Tango.Insights/InsightsManager.cs index 73b74bff6..b187279b4 100644 --- a/Software/Visual_Studio/Tango.Insights/InsightsManager.cs +++ b/Software/Visual_Studio/Tango.Insights/InsightsManager.cs @@ -15,6 +15,9 @@ namespace Tango.Insights { private const string INSIGHTS_COLLECTION = "Insights"; private const string STATUSES_COLLECTION = "Statuses"; + private const string APPLICATION_EXCEPTIONS_COLLECTION = "ApplicationExceptions"; + + private bool _disposed; private static InsightsManager _instance; public static InsightsManager Default @@ -39,6 +42,9 @@ namespace Tango.Insights DatabasePath = databasePath; Directory.CreateDirectory(Path.GetDirectoryName(DatabasePath)); _database = new LiteDatabase($"Filename={DatabasePath}"); + _database.Pragma("TIMEOUT", 10); //Read Timeout + _database.Pragma("UTC_DATE", true); //Keep time as UTC when getting data + _database.Commit(); } public virtual void Dispose() @@ -47,6 +53,7 @@ namespace Tango.Insights { try { + _disposed = true; _database.Dispose(); _database = null; } @@ -69,18 +76,34 @@ namespace Tango.Insights return _database.GetCollection<InsightsStatus>(STATUSES_COLLECTION); } + private ILiteCollection<InsightsApplicationException> GetApplicationExceptionsCollection() + { + return _database.GetCollection<InsightsApplicationException>(APPLICATION_EXCEPTIONS_COLLECTION); + } + public virtual void InsertFrame(InsightsFrame frame) { + if (_disposed) return; + var collection = GetInsightsCollection(); collection.Insert(frame); } public virtual void InsertStatus(InsightsStatus status) { + if (_disposed) return; var collection = GetStatusesCollection(); collection.Insert(status); } + public virtual void InsertApplicationException(InsightsApplicationException appException) + { + if (_disposed) return; + var collection = GetApplicationExceptionsCollection(); + appException.Time = appException.Time.Subtract(TimeSpan.FromSeconds(30)); + collection.Insert(appException); + } + public virtual List<InsightsFrame> GetFrames(DateTime startUTC, DateTime endUTC) { var collection = GetInsightsCollection(); @@ -93,20 +116,36 @@ namespace Tango.Insights return collection.Find(x => x.Time >= startUTC && x.Time <= endUTC).ToList().OrderBy(x => x.Time).ToList(); } + public virtual List<InsightsApplicationException> GetApplicationExceptions(DateTime startUTC, DateTime endUTC) + { + var collection = GetApplicationExceptionsCollection(); + return collection.Find(x => x.Time >= startUTC && x.Time <= endUTC).ToList().OrderBy(x => x.Time).ToList(); + } + public virtual int DeleteFrames(DateTime maxDateUTC) { + if (_disposed) return 0; var collection = GetInsightsCollection(); return collection.DeleteMany(x => x.Time < maxDateUTC); } public virtual int DeleteStatuses(DateTime maxDateUTC) { + if (_disposed) return 0; var collection = GetStatusesCollection(); return collection.DeleteMany(x => x.Time < maxDateUTC); } + public virtual int DeleteApplicationExceptions(DateTime maxDateUTC) + { + if (_disposed) return 0; + var collection = GetApplicationExceptionsCollection(); + return collection.DeleteMany(x => x.Time < maxDateUTC); + } + public DateTime? GetFramesMinDate() { + if (_disposed) return null; var collection = GetInsightsCollection(); if (collection.Count() > 0) @@ -133,9 +172,10 @@ namespace Tango.Insights Description = x.Description }) .ToList() + .Where(x => (EventTypes)x.EventCode != EventTypes.APPLICATION_EXCEPTION) .Select(x => new InsightsEvent() { - Time = new DateTime(x.Time.Ticks, DateTimeKind.Utc), + Time = x.Time, EventCode = x.EventCode, Description = ((EventTypes)x.EventCode == EventTypes.JOB_FAILED ? x.Description : null) }) diff --git a/Software/Visual_Studio/Tango.Insights/Tango.Insights.csproj b/Software/Visual_Studio/Tango.Insights/Tango.Insights.csproj index 1e440a62c..ed136a8c6 100644 --- a/Software/Visual_Studio/Tango.Insights/Tango.Insights.csproj +++ b/Software/Visual_Studio/Tango.Insights/Tango.Insights.csproj @@ -44,6 +44,7 @@ <Compile Include="..\Versioning\GlobalVersionInfo.cs"> <Link>GlobalVersionInfo.cs</Link> </Compile> + <Compile Include="InsightsApplicationException.cs" /> <Compile Include="InsightsEvent.cs" /> <Compile Include="InsightsFile.cs" /> <Compile Include="InsightsHelper.cs" /> diff --git a/Software/Visual_Studio/Tango.Logging/GlobalExceptionTrapper.cs b/Software/Visual_Studio/Tango.Logging/GlobalExceptionTrapper.cs index fc791ff4a..3409ffdc4 100644 --- a/Software/Visual_Studio/Tango.Logging/GlobalExceptionTrapper.cs +++ b/Software/Visual_Studio/Tango.Logging/GlobalExceptionTrapper.cs @@ -21,6 +21,7 @@ namespace Tango.Logging public class WpfGlobalExceptionTrapper : IGlobalExceptionTrapper { private DateTime _lastGlobalExceptionTime = DateTime.Now.AddMinutes(-1); + private Application _app; /// <summary> /// Occurs when the global exception trapper has detected an unhandled exception. @@ -33,6 +34,7 @@ namespace Tango.Logging /// <param name="app">The application.</param> public void Initialize(Application app) { + _app = app; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; app.Dispatcher.UnhandledException += Dispatcher_UnhandledException; Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; @@ -40,6 +42,17 @@ namespace Tango.Logging } /// <summary> + /// Use only when need to simulate application crash! + /// </summary> + public void Disable() + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + _app.Dispatcher.UnhandledException -= Dispatcher_UnhandledException; + Application.Current.DispatcherUnhandledException -= Current_DispatcherUnhandledException; + TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException; + } + + /// <summary> /// Handles the UnobservedTaskException event of the TaskScheduler control. /// </summary> /// <param name="sender">The source of the event.</param> diff --git a/Software/Visual_Studio/Tango.Transport/GenericMessageSerializer.cs b/Software/Visual_Studio/Tango.Transport/GenericMessageSerializer.cs index bb483e19a..6368a7754 100644 --- a/Software/Visual_Studio/Tango.Transport/GenericMessageSerializer.cs +++ b/Software/Visual_Studio/Tango.Transport/GenericMessageSerializer.cs @@ -10,6 +10,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Core.Bson; using Tango.PMR; using Tango.PMR.Common; using Tango.PMR.Integration; @@ -18,60 +19,11 @@ namespace Tango.Transport { public static class GenericMessageSerializer { - private class DateTimeConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return typeof(DateTime) == objectType - || typeof(DateTime?) == objectType; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var dateTimeOffset = (DateTime)value; - // Serialize DateTimeOffset as round-trip formatted string - serializer.Serialize(writer, dateTimeOffset.ToString("O")); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Date) - return null; - - DateTime dt; - - var dateWithOffset = (String)reader.Value; - - if (String.IsNullOrEmpty(dateWithOffset)) - return null; - - if (DateTime.TryParseExact(dateWithOffset, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dt)) - return dt; - - return null; - } - - } - - private class DateTimeContractResolver : DefaultContractResolver - { - protected override JsonContract CreateContract(Type objectType) - { - var contract = base.CreateContract(objectType); - - if (objectType == typeof(DateTime) || objectType == typeof(DateTime?)) - contract.Converter = new DateTimeConverter(); - - return contract; - } - } - private static JsonSerializer _serializer; static GenericMessageSerializer() { - _serializer = new JsonSerializer() { ContractResolver = new DateTimeContractResolver() }; - _serializer.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; + _serializer = new BsonUtcSerializer(); ProtoBuf.Meta.RuntimeTypeModel.Default.AutoAddMissingTypes = true; ProtoBuf.Meta.RuntimeTypeModel.Default.AutoAddProtoContractTypesOnly = false; |
