├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── images ├── button.png ├── limits-modal.png ├── memory-modal.png ├── trace-list-modal.png ├── trace-modal-methods.png ├── trace-modal-muted.png ├── trace-modal-signals.png └── trace-modal-snapshots.png ├── site └── WebVella.BlazorTrace.Site │ ├── App.razor │ ├── Components │ ├── Test1.razor │ ├── Test1.razor.cs │ └── Test2.razor │ ├── FodyWeavers.xml │ ├── Layout │ ├── MainLayout.razor │ └── MainLayout.razor.css │ ├── Pages │ ├── Home.razor │ └── Page.razor │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── WebVella.BlazorTrace.Site.csproj │ ├── _Imports.razor │ └── wwwroot │ ├── favicon.png │ ├── icon-192.png │ ├── icon-512.png │ ├── index.html │ ├── manifest.webmanifest │ ├── service-worker.js │ └── service-worker.published.js ├── src ├── WebVella.BlazorTrace.sln └── WebVella.BlazorTrace │ ├── Attributes │ └── WvBlazorTraceAttribute.cs │ ├── Components │ ├── General │ │ └── WvBlazorTraceModalOverlay.razor │ ├── WvBlazorTrace │ │ ├── WvBlazorTrace.razor │ │ ├── WvBlazorTraceBody.razor │ │ ├── WvBlazorTraceBody.razor.cs │ │ ├── WvBlazorTraceMethodMenu.razor │ │ ├── WvBlazorTraceMuteMenu.razor │ │ ├── WvBlazorTraceRow.razor │ │ ├── WvBlazorTraceSignalMenu.razor │ │ ├── WvBlazorTraceSignalRow.razor │ │ └── WvBlazorTraceSnapshotMenu.razor │ ├── WvBlazorTraceLimitInfoModal.razor │ ├── WvBlazorTraceLimitInfoModal.razor.cs │ ├── WvBlazorTraceLimitInfoSignalModal.razor │ ├── WvBlazorTraceLimitInfoSignalModal.razor.cs │ ├── WvBlazorTraceLimitModal.razor │ ├── WvBlazorTraceLimitModal.razor.cs │ ├── WvBlazorTraceListModal.razor │ ├── WvBlazorTraceListModal.razor.cs │ ├── WvBlazorTraceMemoryModal.razor │ ├── WvBlazorTraceMemoryModal.razor.cs │ ├── WvBlazorTraceMuteLimitModal.razor │ ├── WvBlazorTraceMuteLimitModal.razor.cs │ ├── WvBlazorTraceMuteMemoryModal.razor │ ├── WvBlazorTraceMuteMemoryModal.razor.cs │ ├── WvBlazorTraceMuteMethodModal.razor │ ├── WvBlazorTraceMuteMethodModal.razor.cs │ ├── WvBlazorTraceMuteSignalModal.razor │ ├── WvBlazorTraceMuteSignalModal.razor.cs │ ├── WvBlazorTraceMuteSignalTraceModal.razor │ ├── WvBlazorTraceMuteSignalTraceModal.razor.cs │ ├── WvBlazorTraceMuteTraceModal.razor │ ├── WvBlazorTraceMuteTraceModal.razor.cs │ ├── WvBlazorTraceSignalLimitModal.razor │ ├── WvBlazorTraceSignalLimitModal.razor.cs │ ├── WvBlazorTraceSignalTraceListModal.razor │ ├── WvBlazorTraceSignalTraceListModal.razor.cs │ └── _Imports.razor │ ├── FodyWeavers.xml │ ├── Models │ ├── WvBlazorTraceComponentBase.cs │ ├── WvBlazorTraceConfiguration.cs │ ├── WvButtonPosition.cs │ ├── WvCall.cs │ ├── WvLocalStore.cs │ ├── WvMethodTraceRow.cs │ ├── WvSignalTraceRow.cs │ ├── WvSnapshot.cs │ ├── WvSnapshotListItem.cs │ ├── WvSnapshotMemoryComparison.cs │ ├── WvSnapshotMethodComparison.cs │ ├── WvSnapshotSavingState.cs │ ├── WvSnapshotSignalComparison.cs │ ├── WvTraceInfo.cs │ ├── WvTraceMemoryInfo.cs │ ├── WvTraceMethodOptions.cs │ ├── WvTraceModalData.cs │ ├── WvTraceModalMenuItem.cs │ ├── WvTraceMute.cs │ ├── WvTraceMuteType.cs │ ├── WvTraceQueueAction.cs │ ├── WvTraceSession.cs │ ├── WvTraceSignalOptions.cs │ └── WvUnionData.cs │ ├── Services │ ├── JsService.cs │ ├── WvBlazorTraceConfigurationService.cs │ ├── WvBlazorTraceInjection.cs │ ├── WvBlazorTraceService.MethodCalls.cs │ ├── WvBlazorTraceService.Modal.cs │ ├── WvBlazorTraceService.Queue.cs │ ├── WvBlazorTraceService.Signals.cs │ ├── WvBlazorTraceService.Store.cs │ ├── WvBlazorTraceService.Utils.cs │ └── WvBlazorTraceService.cs │ ├── Styles │ ├── index.less │ ├── wv-trace-button.less │ ├── wv-trace-modal.less │ └── wv-trace-nav.less │ ├── TraceView.razor │ ├── Utility │ ├── CompressionUtility.cs │ ├── EnumExtensions.cs │ ├── MemorySizeCalculator.cs │ ├── WvModalUtility.cs │ ├── WvTraceUtility.Converters.cs │ ├── WvTraceUtility.Info.cs │ ├── WvTraceUtility.Memory.cs │ ├── WvTraceUtility.ModelHelpers.cs │ ├── WvTraceUtility.Mute.cs │ └── WvTraceUtility.cs │ ├── WebVella.BlazorTrace.csproj │ ├── WvConstants.cs │ ├── compilerconfig.json │ ├── compilerconfig.json.defaults │ ├── scripts.js │ ├── styles.css │ └── styles.min.css └── tests └── WebVella.BlazorTrace.Tests ├── Models ├── BaseTest.cs └── TestComponent.cs ├── WebVella.BlazorTrace.Tests.csproj └── WvBlazorTraceService ├── WvBlazorTraceServiceTests.Limits.cs ├── WvBlazorTraceServiceTests.MethodCalls.cs ├── WvBlazorTraceServiceTests.Modal.cs └── WvBlazorTraceServiceTests.Mute.cs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: webvella 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v1.0.6 2 | - OPTIMIZATION: memory size calculation optimization for large repeatable objects. 3 | - OPTIMIZATION: adding compression for snapshots in local storage. 4 | - OPTIMIZATION: changing documents to instruct SignalR Hub Message Size increase to 10 MB from the current 1MB, which is needed for bigger projects with large snapshots. 5 | 6 | # v1.0.5 7 | - FIX: adding missing JsonIgnores (delete localstorage if problems occur) 8 | 9 | # v1.0.4 10 | 11 | - FEATURE: Create "Mute" trace functionality to mute tracers based on module, component, component instance, method or custom data 12 | - OPTIMIZATION: Virtualize the result rows for scalable interface 13 | - FEATURE: Create "Clear Current" session functionality to quickly flush all the current tracers. 14 | 15 | # v1.0.3 16 | - FEATURE: Support .net8 and .net9 by @jhsheets in #6 17 | 18 | # v1.0.0 19 | - FEATURE: Initial Releat 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 WebVella 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /images/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/button.png -------------------------------------------------------------------------------- /images/limits-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/limits-modal.png -------------------------------------------------------------------------------- /images/memory-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/memory-modal.png -------------------------------------------------------------------------------- /images/trace-list-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/trace-list-modal.png -------------------------------------------------------------------------------- /images/trace-modal-methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/trace-modal-methods.png -------------------------------------------------------------------------------- /images/trace-modal-muted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/trace-modal-muted.png -------------------------------------------------------------------------------- /images/trace-modal-signals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/trace-modal-signals.png -------------------------------------------------------------------------------- /images/trace-modal-snapshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/images/trace-modal-snapshots.png -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/App.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
13 | @* <-- INSERT HERE *@ -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Components/Test1.razor: -------------------------------------------------------------------------------- 1 | 
2 |
3 | Test 1 Counter: @_counter 4 |
5 |
6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Components/Test1.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace WebVella.BlazorTrace.Site.Components 4 | { 5 | [WvBlazorTrace] 6 | public partial class Test1 : ComponentBase 7 | { 8 | [Parameter] public string? InstanceTag { get; set; } 9 | private int _counter = 0; 10 | [Inject] public IWvBlazorTraceService WvBlazorTraceService { get; set; } 11 | 12 | private void _countTest1() 13 | { 14 | _counter++; 15 | WvBlazorTraceService.OnSignal(caller: this, signalName: "counter", instanceTag: InstanceTag, 16 | customData: $"counter:{_counter}", 17 | options: new Models.WvTraceSignalOptions 18 | { 19 | CallLimit = 0 20 | }); 21 | 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Components/Test2.razor: -------------------------------------------------------------------------------- 1 | @using System.Diagnostics 2 | @using WebVella.BlazorTrace.Models 3 | @inject IWvBlazorTraceService WvBlazorTraceService 4 |
5 |
6 | Test 1 Parent: @ParentCounter 7 |
8 |
9 | Test 2 Instance 1 Counter: @_counter 10 |
11 |
12 | 13 |
14 |
15 | 16 | @code { 17 | [Parameter] public int ParentCounter { get; set; } = 0; 18 | [Parameter] public string? InstanceTag { get; set; } 19 | private bool _enableTrace = true; 20 | private int _counter = 0; 21 | private List _list = new(); 22 | private static string _staticTest = Guid.NewGuid().ToString(); 23 | 24 | protected override void OnInitialized() 25 | { 26 | if (_enableTrace) 27 | WvBlazorTraceService.OnEnter(this, instanceTag: InstanceTag); 28 | 29 | base.OnInitialized(); 30 | for (int i = 0; i < 5; i++) 31 | { 32 | _list.Add(Guid.NewGuid()); 33 | if (_enableTrace) 34 | WvBlazorTraceService.OnSignal(this, signalName: "test-signal", instanceTag: InstanceTag, 35 | customData:$"index={i}", 36 | options: new WvTraceSignalOptions 37 | { 38 | CallLimit = 5 - i 39 | }); 40 | } 41 | 42 | if (_enableTrace) 43 | WvBlazorTraceService.OnExit(this, instanceTag: InstanceTag, options: new WvTraceMethodOptions 44 | { 45 | MemoryLimitTotalBytes = 1, 46 | MemoryLimitDeltaBytes = 1, 47 | CallLimit = 1, 48 | DurationLimitMS = 1 49 | }); 50 | } 51 | 52 | protected override async Task OnAfterRenderAsync(bool firstRender) 53 | { 54 | if (_enableTrace) 55 | WvBlazorTraceService.OnEnter(this, firstRender: firstRender, instanceTag: InstanceTag); 56 | 57 | base.OnAfterRender(firstRender); 58 | await Task.Delay(50); 59 | 60 | if (_enableTrace) 61 | WvBlazorTraceService.OnExit(this, firstRender: firstRender, instanceTag: InstanceTag); 62 | } 63 | 64 | protected override void OnParametersSet() 65 | { 66 | if (_enableTrace) 67 | WvBlazorTraceService.OnEnter(this, instanceTag: InstanceTag); 68 | 69 | base.OnParametersSet(); 70 | 71 | if (_enableTrace) 72 | WvBlazorTraceService.OnExit(this, instanceTag: InstanceTag); 73 | } 74 | 75 | protected override bool ShouldRender() 76 | { 77 | if (_enableTrace) 78 | WvBlazorTraceService.OnEnter(this, instanceTag: InstanceTag); 79 | 80 | if (_enableTrace) 81 | WvBlazorTraceService.OnExit(this, instanceTag: InstanceTag); 82 | return base.ShouldRender(); 83 | } 84 | 85 | private void _countTest2() 86 | { 87 | if (_enableTrace) 88 | WvBlazorTraceService.OnEnter(component: this, instanceTag: InstanceTag); 89 | 90 | _counter++; 91 | 92 | if (_enableTrace) 93 | WvBlazorTraceService.OnExit(component: this, instanceTag: InstanceTag); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 |
3 | Home 4 | | 5 | Page 6 |
7 |
8 | @Body 9 |
10 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Layout/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row ::deep .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | text-decoration: none; 28 | } 29 | 30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { 31 | text-decoration: underline; 32 | } 33 | 34 | .top-row ::deep a:first-child { 35 | overflow: hidden; 36 | text-overflow: ellipsis; 37 | } 38 | 39 | @media (max-width: 640.98px) { 40 | .top-row { 41 | justify-content: space-between; 42 | } 43 | 44 | .top-row ::deep a, .top-row ::deep .btn-link { 45 | margin-left: 0; 46 | } 47 | } 48 | 49 | @media (min-width: 641px) { 50 | .page { 51 | flex-direction: row; 52 | } 53 | 54 | .sidebar { 55 | width: 250px; 56 | height: 100vh; 57 | position: sticky; 58 | top: 0; 59 | } 60 | 61 | .top-row { 62 | position: sticky; 63 | top: 0; 64 | z-index: 1; 65 | } 66 | 67 | .top-row.auth ::deep a:first-child { 68 | flex: 1; 69 | text-align: right; 70 | width: 0; 71 | } 72 | 73 | .top-row, article { 74 | padding-left: 2rem !important; 75 | padding-right: 1.5rem !important; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Pages/Home.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | Home 3 |

Home Page

4 | 5 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Pages/Page.razor: -------------------------------------------------------------------------------- 1 | @page "/page" 2 | Page 3 |

Addon Page

4 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Web; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | 4 | //how to add fody support 5 | //1. add module with name ot attribute 6 | //2. add in project file nuget ref -> 7 | //3. add file FodyWeavers.xml 8 | 9 | [module: WvBlazorTrace] 10 | 11 | namespace WebVella.BlazorTrace.Site; 12 | public class Program 13 | { 14 | public static async Task Main(string[] args) 15 | { 16 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 17 | builder.RootComponents.Add("#app"); 18 | builder.RootComponents.Add("head::after"); 19 | 20 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 21 | builder.Services.AddBlazorTrace(new WvBlazorTraceConfiguration() 22 | { 23 | #if DEBUG 24 | EnableTracing = true, 25 | AutoShowModal = true, 26 | #else 27 | EnableTracing = false, 28 | #endif 29 | EnableF1Shortcut = true, 30 | MemoryIncludeAssemblyList = new(){ 31 | "WebVella.BlazorTrace.Site" 32 | } 33 | }); 34 | 35 | await builder.Build().RunAsync(); 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "http": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": true, 8 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 9 | "applicationUrl": "http://localhost:5066", 10 | "environmentVariables": { 11 | "ASPNETCORE_ENVIRONMENT": "Development" 12 | } 13 | }, 14 | "https": { 15 | "commandName": "Project", 16 | "dotnetRunMessages": true, 17 | "launchBrowser": true, 18 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 19 | "applicationUrl": "https://localhost:7291;http://localhost:5066", 20 | "environmentVariables": { 21 | "ASPNETCORE_ENVIRONMENT": "Development" 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/WebVella.BlazorTrace.Site.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | service-worker-assets.js 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using WebVella.BlazorTrace.Site 10 | @using WebVella.BlazorTrace.Site.Layout 11 | @using WebVella.BlazorTrace.Site.Components 12 | @using WebVella.BlazorTrace.Components 13 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/site/WebVella.BlazorTrace.Site/wwwroot/favicon.png -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/site/WebVella.BlazorTrace.Site/wwwroot/icon-192.png -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebVella/WebVella.BlazorTrace/967af315e6d911c08b3d1db92d0146b7d28488a2/site/WebVella.BlazorTrace.Site/wwwroot/icon-512.png -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | WebVella.BlazorTrace.Site 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WebVella.BlazorTrace.Site", 3 | "short_name": "WebVella.BlazorTrace.Site", 4 | "id": "./", 5 | "start_url": "./", 6 | "display": "standalone", 7 | "background_color": "#ffffff", 8 | "theme_color": "#03173d", 9 | "prefer_related_applications": false, 10 | "icons": [ 11 | { 12 | "src": "icon-512.png", 13 | "type": "image/png", 14 | "sizes": "512x512" 15 | }, 16 | { 17 | "src": "icon-192.png", 18 | "type": "image/png", 19 | "sizes": "192x192" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/service-worker.js: -------------------------------------------------------------------------------- 1 | // In development, always fetch from the network and do not enable offline support. 2 | // This is because caching would make development more difficult (changes would not 3 | // be reflected on the first load after each change). 4 | self.addEventListener('fetch', () => { }); 5 | -------------------------------------------------------------------------------- /site/WebVella.BlazorTrace.Site/wwwroot/service-worker.published.js: -------------------------------------------------------------------------------- 1 | // Caution! Be sure you understand the caveats before publishing an application with 2 | // offline support. See https://aka.ms/blazor-offline-considerations 3 | 4 | self.importScripts('./service-worker-assets.js'); 5 | self.addEventListener('install', event => event.waitUntil(onInstall(event))); 6 | self.addEventListener('activate', event => event.waitUntil(onActivate(event))); 7 | self.addEventListener('fetch', event => event.respondWith(onFetch(event))); 8 | 9 | const cacheNamePrefix = 'offline-cache-'; 10 | const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; 11 | const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ]; 12 | const offlineAssetsExclude = [ /^service-worker\.js$/ ]; 13 | 14 | // Replace with your base path if you are hosting on a subfolder. Ensure there is a trailing '/'. 15 | const base = "/"; 16 | const baseUrl = new URL(base, self.origin); 17 | const manifestUrlList = self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href); 18 | 19 | async function onInstall(event) { 20 | console.info('Service worker: Install'); 21 | 22 | // Fetch and cache all matching items from the assets manifest 23 | const assetsRequests = self.assetsManifest.assets 24 | .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) 25 | .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) 26 | .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); 27 | await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); 28 | } 29 | 30 | async function onActivate(event) { 31 | console.info('Service worker: Activate'); 32 | 33 | // Delete unused caches 34 | const cacheKeys = await caches.keys(); 35 | await Promise.all(cacheKeys 36 | .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName) 37 | .map(key => caches.delete(key))); 38 | } 39 | 40 | async function onFetch(event) { 41 | let cachedResponse = null; 42 | if (event.request.method === 'GET') { 43 | // For all navigation requests, try to serve index.html from cache, 44 | // unless that request is for an offline resource. 45 | // If you need some URLs to be server-rendered, edit the following check to exclude those URLs 46 | const shouldServeIndexHtml = event.request.mode === 'navigate' 47 | && !manifestUrlList.some(url => url === event.request.url); 48 | 49 | const request = shouldServeIndexHtml ? 'index.html' : event.request; 50 | const cache = await caches.open(cacheName); 51 | cachedResponse = await cache.match(request); 52 | } 53 | 54 | return cachedResponse || fetch(event.request); 55 | } 56 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.13.36105.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebVella.BlazorTrace", ".\WebVella.BlazorTrace\WebVella.BlazorTrace.csproj", "{17B69929-6020-4C11-9300-16186BBE2B71}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebVella.BlazorTrace.Site", "..\site\WebVella.BlazorTrace.Site\WebVella.BlazorTrace.Site.csproj", "{46488E6F-6DDB-4582-9CF1-E30C7F37A71D}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebVella.BlazorTrace.Tests", "..\tests\WebVella.BlazorTrace.Tests\WebVella.BlazorTrace.Tests.csproj", "{AD3ED490-7A62-46E3-82E7-D5BB833281E2}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {17B69929-6020-4C11-9300-16186BBE2B71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {17B69929-6020-4C11-9300-16186BBE2B71}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {17B69929-6020-4C11-9300-16186BBE2B71}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {17B69929-6020-4C11-9300-16186BBE2B71}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {46488E6F-6DDB-4582-9CF1-E30C7F37A71D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {46488E6F-6DDB-4582-9CF1-E30C7F37A71D}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {46488E6F-6DDB-4582-9CF1-E30C7F37A71D}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {46488E6F-6DDB-4582-9CF1-E30C7F37A71D}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {AD3ED490-7A62-46E3-82E7-D5BB833281E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {AD3ED490-7A62-46E3-82E7-D5BB833281E2}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {AD3ED490-7A62-46E3-82E7-D5BB833281E2}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {AD3ED490-7A62-46E3-82E7-D5BB833281E2}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {20F00A6F-D9E2-477C-955D-8AB6103417B0} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Attributes/WvBlazorTraceAttribute.cs: -------------------------------------------------------------------------------- 1 | using MethodDecorator.Fody.Interfaces; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using WebVella.BlazorTrace; 7 | 8 | [module: WvBlazorTrace] 9 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Module, Inherited = true)] 10 | public class WvBlazorTraceAttribute : Attribute, IMethodDecorator 11 | { 12 | private ComponentBase _targetInstance = default!; 13 | private MethodBase _method = default!; 14 | private bool _isAsync = false; 15 | public void Init(object instance, MethodBase method, object[] args) 16 | { 17 | _targetInstance = (instance as ComponentBase)!; 18 | _method = method; 19 | _isAsync = method.IsDefined(typeof(AsyncStateMachineAttribute), false); 20 | } 21 | 22 | public void OnEntry() 23 | { 24 | var traceService = WvBlazorTraceService.GetScopedService(); 25 | if (traceService is not null) 26 | { 27 | traceService.OnEnter(_targetInstance, methodName: _method.Name); 28 | } 29 | } 30 | 31 | public void OnExit() 32 | { 33 | var traceService = WvBlazorTraceService.GetScopedService(); 34 | if (!_isAsync && traceService is not null) 35 | { 36 | traceService.OnExit(_targetInstance, methodName: _method.Name); 37 | } 38 | } 39 | 40 | public async Task OnTaskContinuation(Task task) 41 | { 42 | await task; // Ensure the task completes before proceeding 43 | 44 | var traceService = WvBlazorTraceService.GetScopedService(); 45 | if (traceService is not null) 46 | { 47 | traceService.OnExit(_targetInstance, methodName: _method.Name); 48 | } 49 | } 50 | 51 | public void OnException(Exception exception) 52 | { 53 | // do nothing 54 | } 55 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/General/WvBlazorTraceModalOverlay.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | 4 |
8 | @code { 9 | [Parameter] public EventCallback OnHide { get; set; } 10 | [Parameter] public int NestLevel { get; set; } = 0; 11 | private string _style { get => $"z-index:{(20000 + (2*NestLevel))}"; } 12 | private async Task _hideClick() 13 | => await OnHide.InvokeAsync(); 14 | 15 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTrace/WvBlazorTrace.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @if (WvBlazorTraceConfigurationService.GetConfiguraion().EnableTracing) 4 | { 5 | 6 | } 7 | 8 | @code { 9 | [Inject] public IWvBlazorTraceConfigurationService WvBlazorTraceConfigurationService { get; set; } = default!; 10 | // PARAMS 11 | ////////////////////////////////////////////////// 12 | /// 13 | /// the 'heart button' position on the screen 14 | /// 15 | [Parameter] public WvButtonPosition Position { get; set; } = WvButtonPosition.RightTop; 16 | /// 17 | /// the background color of the 'heart button' 18 | /// 19 | [Parameter] public string ButtonColor { get; set; } = "#be123c"; 20 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTrace/WvBlazorTraceMethodMenu.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | 4 | @if (Data is not null && Data.Request is not null && Data.Request!.IsMethodMenu) 5 | { 6 | 7 | 8 | 9 | 20 | 25 | 30 | 35 | 44 | 54 | 63 | 72 | 73 | @foreach (var item in Data.MethodTraceRows.Where(x => x.IsPinned)) 74 | { 75 | 81 | } 82 | 83 | 84 | @if (Loading) 85 | { 86 | 87 | 88 | 89 | } 90 | else 91 | { 92 | 93 | 99 | 100 | @if (Data.MethodTraceRows.Count == 0) 101 | { 102 | 103 | 104 | 105 | } 106 | } 107 | 108 |
10 | @if (Data?.Request is not null && Data.Request.MethodsFilter.HasFilter) 11 | { 12 | 18 | } 19 | 21 | 24 | 26 | 29 | 31 | 34 | 36 | 37 | 38 | @foreach (var option in Enum.GetValues()) 39 | { 40 | 41 | } 42 | 43 | 45 | 47 | 48 | @foreach (var option in Enum.GetValues()) 49 | { 50 | 51 | } 52 | 53 | 55 | 56 | 57 | @foreach (var option in Enum.GetValues()) 58 | { 59 | 60 | } 61 | 62 | 64 | 65 | 66 | @foreach (var option in Enum.GetValues()) 67 | { 68 | 69 | } 70 | 71 |
Loading ....
No tracers are logged yet
109 | } 110 | @code { 111 | [Parameter] public WvTraceModalData? Data { get; set; } = null; 112 | [Parameter] public bool Loading { get; set; } = false; 113 | [Parameter] public EventCallback ClearFilter { get; set; } 114 | [Parameter] public EventCallback SubmitFilter { get; set; } = default!; 115 | [Parameter] public EventCallback ShowTraceListModal { get; set; } 116 | [Parameter] public EventCallback ShowMemoryModal { get; set; } 117 | [Parameter] public EventCallback PinClicked { get; set; } 118 | [Parameter] public EventCallback ShowLimitModal { get; set; } 119 | [Parameter] public EventCallback ShowTraceMuteModal { get; set; } 120 | 121 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTrace/WvBlazorTraceMuteMenu.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | 4 | @if (Data is not null && Data.Request is not null && Data.Request!.IsTraceMuteMenu) 5 | { 6 | 7 | 8 | 9 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 97 | 98 | 99 | @if (Data.MutedTraceRows.Count == 0) 100 | { 101 | 102 | 103 | 104 | } 105 | 106 |
10 | @if (Data?.Request is not null && Data.Request.MutedFilter.HasFilter) 11 | { 12 | 18 | } 19 | 21 | 24 | 26 | 29 | 31 | 34 | 36 | 39 | 41 | 44 | 46 | 49 | 51 | 54 | 56 | 59 | 61 | 64 |
72 | 78 | @((MarkupString)item.Type.WvBTToDescriptionString())@((MarkupString)(String.IsNullOrWhiteSpace(item.Module) ? "undefined" : item.Module))@((MarkupString)(String.IsNullOrWhiteSpace(item.ComponentName) ? "undefined" : item.ComponentName))@((MarkupString)(String.IsNullOrWhiteSpace(item.InstanceTag) ? "undefined" : item.InstanceTag))@((MarkupString)(String.IsNullOrWhiteSpace(item.Method) ? "undefined" : item.Method))@((MarkupString)(String.IsNullOrWhiteSpace(item.Signal) ? "undefined" : item.Signal))@((MarkupString)(String.IsNullOrWhiteSpace(item.Field) ? "undefined" : item.Field))@((MarkupString)(String.IsNullOrWhiteSpace(item.OnEnterCustomData) ? "undefined" : item.OnEnterCustomData)) 88 | @if (item.IsPinned is not null) 89 | { 90 | @item.IsPinned.Value.ToString() 91 | } 92 | else 93 | { 94 | undefined 95 | } 96 |
No traces are muted yet
107 | } 108 | @code { 109 | [Parameter] public WvTraceModalData? Data { get; set; } = null; 110 | [Parameter] public EventCallback ClearFilter { get; set; } 111 | [Parameter] public EventCallback SubmitFilter { get; set; } = default!; 112 | [Parameter] public EventCallback MuteTraceChange { get; set; } 113 | 114 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTrace/WvBlazorTraceSignalMenu.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | 4 | @if (Data is not null && Data.Request is not null && Data.Request!.IsSignalMenu) 5 | { 6 | 7 | 8 | 9 | 20 | 25 | 34 | 46 | 47 | @foreach (var item in Data.SignalTraceRows.Where(x => x.IsPinned)) 48 | { 49 | 54 | } 55 | 56 | 57 | @if (Loading) 58 | { 59 | 60 | 61 | 62 | } 63 | else 64 | { 65 | 66 | 71 | 72 | @if (Data.SignalTraceRows.Count == 0) 73 | { 74 | 75 | 76 | 77 | } 78 | } 79 | 80 |
10 | @if (Data?.Request is not null && Data.Request.SignalsFilter.HasFilter) 11 | { 12 | 18 | } 19 | 21 | 24 | 26 | 27 | 28 | @foreach (var option in Enum.GetValues()) 29 | { 30 | 31 | } 32 | 33 | 35 | 36 | 37 | @foreach (var option in new List { 38 | WvTraceModalLimitsFilter.HasLimitHits, 39 | WvTraceModalLimitsFilter.ZeroLimitHits 40 | }) 41 | { 42 | 43 | } 44 | 45 |
Loading ....
No tracers are logged yet
81 | } 82 | @code { 83 | [Parameter] public WvTraceModalData? Data { get; set; } = null; 84 | [Parameter] public bool Loading { get; set; } = false; 85 | [Parameter] public EventCallback ClearFilter { get; set; } 86 | [Parameter] public EventCallback SubmitFilter { get; set; } = default!; 87 | [Parameter] public EventCallback ShowTraceListModal { get; set; } 88 | [Parameter] public EventCallback PinClicked { get; set; } 89 | [Parameter] public EventCallback ShowLimitModal { get; set; } 90 | [Parameter] public EventCallback ShowTraceMuteModal { get; set; } 91 | 92 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTrace/WvBlazorTraceSignalRow.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | 3 | @if (Item is not null) 4 | { 5 | 6 | 7 | @if (Item.IsPinned) 8 | { 9 | 14 | } 15 | else 16 | { 17 | 22 | } 23 | 28 | 29 | 30 | @Item.SignalName 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 |
39 |
40 |
@Item.TraceList.Count
41 |
@((MarkupString)Item.SignalComparison.TraceListChangeHtml)
42 |
43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 |
51 |
@((MarkupString)Item.LimitsHtml)
52 | 53 | 54 | 55 | } 56 | @code { 57 | [Parameter] public string? Class { get; set; } 58 | [Parameter] public WvSignalTraceRow? Item { get; set; } 59 | [Parameter] public EventCallback OnTraceListView { get; set; } 60 | [Parameter] public EventCallback OnPin { get; set; } 61 | [Parameter] public EventCallback OnMute { get; set; } 62 | [Parameter] public EventCallback OnLimitView { get; set; } 63 | 64 | private async Task _onTraceListView() => await OnTraceListView.InvokeAsync(Item); 65 | private async Task _onPin() => await OnPin.InvokeAsync(Item); 66 | private async Task _onMute() => await OnMute.InvokeAsync(Item); 67 | private async Task _onLimitView() => await OnLimitView.InvokeAsync(Item); 68 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTrace/WvBlazorTraceSnapshotMenu.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | 4 | @if (Data is not null && Data.Request is not null && Data.Request!.IsSnapshotMenu) 5 | { 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | @foreach (var item in Data.SnapshotList.OrderBy(x => x.CreatedOn)) 16 | { 17 | 18 | 21 | 22 | 27 | 28 | 29 | } 30 | @if (Data.SnapshotList.Count == 0) 31 | { 32 | 33 | 34 | 35 | } 36 | 37 |
created onname
19 | 20 | @item.CreatedOn.ToString("yyyy-MM-dd HH:mm:ss") 23 | 26 |
No snapshots saved yet
38 | } 39 | @code { 40 | [Parameter] public WvTraceModalData? Data { get; set; } = null; 41 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceLimitInfoModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _options is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
optionvalue
call limit@_options.CallLimit
total memory limit@_options.MemoryLimitTotalBytes.WvBTToKilobytesString()
new/delta memory limit@_options.MemoryLimitDeltaBytes.WvBTToKilobytesString()
duration limit@_options.DurationLimitMS.WvBTToDurationMSString()
42 |
43 | 46 |
47 | } 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceLimitInfoModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | using WebVella.BlazorTrace.Utility; 6 | 7 | namespace WebVella.BlazorTrace; 8 | public partial class WvBlazorTraceLimitInfoModal : WvBlazorTraceComponentBase 9 | { 10 | // INJECTS 11 | ////////////////////////////////////////////////// 12 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 13 | 14 | // PARAMETERS 15 | ////////////////////////////////////////////////// 16 | [Parameter] public int NestLevel { get; set; } = 1; 17 | 18 | // LOCAL VARIABLES 19 | ////////////////////////////////////////////////// 20 | private Guid _componentId = Guid.NewGuid(); 21 | private DotNetObjectReference _objectRef = default!; 22 | private bool _escapeListenerEnabled = false; 23 | private bool _modalVisible = false; 24 | private WvTraceMethodOptions? _options = null; 25 | private bool _isEnterOptions = true; 26 | 27 | // LIFECYCLE 28 | /// ////////////////////////////////////////////// 29 | public async ValueTask DisposeAsync() 30 | { 31 | if (_escapeListenerEnabled) 32 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 33 | _objectRef?.Dispose(); 34 | } 35 | protected override void OnInitialized() 36 | { 37 | base.OnInitialized(); 38 | _objectRef = DotNetObjectReference.Create(this); 39 | EnableRenderLock(); 40 | } 41 | 42 | protected override void OnParametersSet() 43 | { 44 | base.OnParametersSet(); 45 | RegenRenderLock(); 46 | } 47 | 48 | // PUBLIC 49 | ////////////////////////////////////////////////// 50 | public async Task Show(WvTraceMethodOptions options, bool isEnterOptions = true) 51 | { 52 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 53 | _escapeListenerEnabled = true; 54 | _options = options; 55 | _isEnterOptions = isEnterOptions; 56 | _modalVisible = true; 57 | RegenRenderLock(); 58 | await InvokeAsync(StateHasChanged); 59 | } 60 | public async Task Hide(bool invokeStateChanged = true) 61 | { 62 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 63 | _escapeListenerEnabled = false; 64 | _options = null; 65 | _isEnterOptions = true; 66 | _modalVisible = false; 67 | RegenRenderLock(); 68 | if (invokeStateChanged) 69 | { 70 | await InvokeAsync(StateHasChanged); 71 | } 72 | } 73 | 74 | [JSInvokable("OnShortcutKey")] 75 | public async Task OnShortcutKey(string code) 76 | { 77 | await Hide(); 78 | } 79 | 80 | //PRIVATE 81 | ///////////////////////////////////////////////// 82 | private string _getTitle() 83 | { 84 | if (_options is null) return String.Empty; 85 | 86 | var sb = new StringBuilder(); 87 | sb.Append($"{(_isEnterOptions ? "OnEnter" : "OnExit")} Limit Options"); 88 | 89 | return sb.ToString(); 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceLimitInfoSignalModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _options is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
optionvalue
call limit@_options.CallLimit
30 |
31 | 34 |
35 | } 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceLimitInfoSignalModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceLimitInfoSignalModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [Parameter] public int NestLevel { get; set; } = 1; 16 | 17 | // LOCAL VARIABLES 18 | ////////////////////////////////////////////////// 19 | private Guid _componentId = Guid.NewGuid(); 20 | private DotNetObjectReference _objectRef = default!; 21 | private bool _escapeListenerEnabled = false; 22 | private bool _modalVisible = false; 23 | private WvTraceSignalOptions? _options = null; 24 | 25 | // LIFECYCLE 26 | /// ////////////////////////////////////////////// 27 | public async ValueTask DisposeAsync() 28 | { 29 | if (_escapeListenerEnabled) 30 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 31 | _objectRef?.Dispose(); 32 | } 33 | protected override void OnInitialized() 34 | { 35 | base.OnInitialized(); 36 | _objectRef = DotNetObjectReference.Create(this); 37 | EnableRenderLock(); 38 | } 39 | 40 | protected override void OnParametersSet() 41 | { 42 | base.OnParametersSet(); 43 | RegenRenderLock(); 44 | } 45 | 46 | // PUBLIC 47 | ////////////////////////////////////////////////// 48 | public async Task Show(WvTraceSignalOptions options) 49 | { 50 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 51 | _escapeListenerEnabled = true; 52 | _options = options; 53 | _modalVisible = true; 54 | RegenRenderLock(); 55 | await InvokeAsync(StateHasChanged); 56 | } 57 | public async Task Hide(bool invokeStateChanged = true) 58 | { 59 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 60 | _escapeListenerEnabled = false; 61 | _options = null; 62 | _modalVisible = false; 63 | RegenRenderLock(); 64 | if (invokeStateChanged) 65 | { 66 | await InvokeAsync(StateHasChanged); 67 | } 68 | } 69 | 70 | [JSInvokable("OnShortcutKey")] 71 | public async Task OnShortcutKey(string code) 72 | { 73 | await Hide(); 74 | } 75 | 76 | //PRIVATE 77 | ///////////////////////////////////////////////// 78 | private string _getTitle() 79 | { 80 | if (_options is null) return String.Empty; 81 | 82 | var sb = new StringBuilder(); 83 | sb.Append($"Limit Options"); 84 | 85 | return sb.ToString(); 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceLimitModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | @if (_row.LimitHits.Count == 0) 43 | { 44 | 45 | 46 | 47 | } 48 | 49 |
limit typestagelimitactual
30 | 35 | @item.Type.WvBTToDescriptionString()@(item.IsOnEnter ? "onEnter" : "OnExit")@item.Limit.GetLimitValueAsString(item.Type)@item.Actual.GetLimitValueAsString(item.Type)
No tracers are logged yet for this method
50 |
51 | 54 |
55 | 56 | } 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceLimitModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceLimitModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [CascadingParameter(Name = "WvBlazorTraceBody")] 12 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 13 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 14 | 15 | // PARAMETERS 16 | ////////////////////////////////////////////////// 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | 19 | // LOCAL VARIABLES 20 | ////////////////////////////////////////////////// 21 | private Guid _componentId = Guid.NewGuid(); 22 | private DotNetObjectReference _objectRef = default!; 23 | private bool _escapeListenerEnabled = false; 24 | private bool _modalVisible = false; 25 | private WvMethodTraceRow? _row = null; 26 | private WvBlazorTraceMuteLimitModal? _limitMuteModal = null; 27 | 28 | // LIFECYCLE 29 | /// ////////////////////////////////////////////// 30 | public async ValueTask DisposeAsync() 31 | { 32 | if (_escapeListenerEnabled) 33 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 34 | _objectRef?.Dispose(); 35 | } 36 | protected override void OnInitialized() 37 | { 38 | base.OnInitialized(); 39 | _objectRef = DotNetObjectReference.Create(this); 40 | EnableRenderLock(); 41 | } 42 | 43 | // PUBLIC 44 | ////////////////////////////////////////////////// 45 | public async Task Show(WvMethodTraceRow row) 46 | { 47 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 48 | _escapeListenerEnabled = true; 49 | _row = row; 50 | _modalVisible = true; 51 | RegenRenderLock(); 52 | await InvokeAsync(StateHasChanged); 53 | } 54 | public async Task Hide(bool invokeStateChanged = true) 55 | { 56 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = false; 58 | _row = null; 59 | _modalVisible = false; 60 | RegenRenderLock(); 61 | if (invokeStateChanged) 62 | { 63 | await InvokeAsync(StateHasChanged); 64 | } 65 | } 66 | 67 | [JSInvokable("OnShortcutKey")] 68 | public async Task OnShortcutKey(string code) 69 | { 70 | await Hide(); 71 | } 72 | 73 | //PRIVATE 74 | ///////////////////////////////////////////////// 75 | private string _getTitle() 76 | { 77 | if (_row is null) return String.Empty; 78 | 79 | var sb = new StringBuilder(); 80 | sb.Append($"{_row.Component}"); 81 | if (!String.IsNullOrWhiteSpace(_row.InstanceTag)) 82 | { 83 | sb.Append($" {_row.InstanceTag}"); 84 | } 85 | sb.Append(""); 86 | sb.Append($"{_row.Method}"); 87 | 88 | return sb.ToString(); 89 | } 90 | 91 | private async Task _onMute(WvTraceSessionLimitHit dataField) 92 | { 93 | if (dataField is null || _row is null) return; 94 | if (_limitMuteModal is null) return; 95 | await _limitMuteModal.Show(_row, dataField); 96 | } 97 | 98 | private async Task _muteChanged() 99 | { 100 | var data = WvBlazorTraceBody.GetData(); 101 | if (data is null || _row is null) return; 102 | 103 | var row = data.MethodTraceRows.FirstOrDefault(x => x.Id == _row.Id); 104 | if (row is null) 105 | { 106 | _row.LimitHits = new(); 107 | } 108 | else 109 | _row = row; 110 | RegenRenderLock(); 111 | await InvokeAsync(StateHasChanged); 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceListModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_row is not null && _modalVisible) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 48 | 49 | 50 | 61 | 62 | 63 | 66 | 67 | 78 | 79 | 80 | 83 | 84 | 85 | @if (_row.TraceList.Count == 0) 86 | { 87 | 88 | 89 | 90 | } 91 | 92 |
durationenterexit
timestampmemorycustom datafirst renderlimitstimestampmemorycustom datafirst renderlimits
42 | 47 | @item.DurationMs.WvBTToDurationMSString()@item.EnteredOn?.WvBTToTimeString() _showMemoryModal(item.TraceId,true))> 51 |
52 | 53 | 54 | 55 | 56 |
57 |
58 | @item.OnEnterMemoryBytes.WvBTToKilobytesString() 59 |
60 |
@item.OnEnterCustomData@item.OnEnterFirstRender.WvBTGetFirstRenderString() 64 | 65 | @item.ExitedOn?.WvBTToTimeString() _showMemoryModal(item.TraceId,false))> 68 |
69 | 70 | 71 | 72 | 73 |
74 |
75 | @item.OnExitMemoryBytes.WvBTToKilobytesString() 76 |
77 |
@item.OnExitCustomData@item.OnExitFirstRender.WvBTGetFirstRenderString() 81 | 82 |
No tracers are logged yet for this method
93 |
94 | 97 |
98 | 99 | 100 | 101 | } 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceListModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceListModal : WvBlazorTraceComponentBase, IAsyncDisposable 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | 19 | // LOCAL VARIABLES 20 | ////////////////////////////////////////////////// 21 | private Guid _componentId = Guid.NewGuid(); 22 | private DotNetObjectReference _objectRef = default!; 23 | private bool _escapeListenerEnabled = false; 24 | private bool _modalVisible = false; 25 | private WvMethodTraceRow? _row = null; 26 | private WvBlazorTraceMemoryModal? _memoryModal = null; 27 | private WvBlazorTraceLimitInfoModal? _limitInfoModal = null; 28 | private WvBlazorTraceMuteTraceModal? _traceMuteModal = null; 29 | // LIFECYCLE 30 | /// ////////////////////////////////////////////// 31 | public async ValueTask DisposeAsync() 32 | { 33 | if (_escapeListenerEnabled) 34 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 35 | _objectRef?.Dispose(); 36 | } 37 | protected override void OnInitialized() 38 | { 39 | base.OnInitialized(); 40 | _objectRef = DotNetObjectReference.Create(this); 41 | EnableRenderLock(); 42 | } 43 | 44 | // PUBLIC 45 | ////////////////////////////////////////////////// 46 | public async Task Show(WvMethodTraceRow row) 47 | { 48 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 49 | _escapeListenerEnabled = true; 50 | _row = row; 51 | _modalVisible = true; 52 | RegenRenderLock(); 53 | await InvokeAsync(StateHasChanged); 54 | } 55 | public async Task Hide(bool invokeStateChanged = true) 56 | { 57 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 58 | _escapeListenerEnabled = false; 59 | _row = null; 60 | _modalVisible = false; 61 | RegenRenderLock(); 62 | if (invokeStateChanged) 63 | { 64 | await InvokeAsync(StateHasChanged); 65 | } 66 | } 67 | 68 | [JSInvokable("OnShortcutKey")] 69 | public async Task OnShortcutKey(string code) 70 | { 71 | await Hide(); 72 | } 73 | 74 | //PRIVATE 75 | ///////////////////////////////////////////////// 76 | private string _getTitle() 77 | { 78 | if (_row is null) return String.Empty; 79 | 80 | var sb = new StringBuilder(); 81 | sb.Append($"{_row.Component}"); 82 | if (!String.IsNullOrWhiteSpace(_row.InstanceTag)) 83 | { 84 | sb.Append($" {_row.InstanceTag}"); 85 | } 86 | sb.Append(""); 87 | sb.Append($"{_row.Method}"); 88 | 89 | return sb.ToString(); 90 | } 91 | 92 | private async Task _showMemoryModal(Guid traceId, bool isOnEnter = true) 93 | { 94 | if (_memoryModal is null || _row is null) return; 95 | await _memoryModal.Show(_row, traceId, isOnEnter); 96 | } 97 | private async Task _showLimitInfoModal(WvTraceSessionMethodTrace trace, bool isOnEnter = true) 98 | { 99 | if (_limitInfoModal is null) return; 100 | await _limitInfoModal.Show(isOnEnter ? trace.OnEnterOptions : trace.OnExitOptions, isOnEnter); 101 | } 102 | private async Task _onMute(WvTraceSessionMethodTrace dataField) 103 | { 104 | if (dataField is null || _row is null) return; 105 | if (_traceMuteModal is null) return; 106 | await _traceMuteModal.Show(_row, dataField); 107 | } 108 | 109 | private async Task _muteChanged() 110 | { 111 | var data = WvBlazorTraceBody.GetData(); 112 | if (data is null || _row is null) return; 113 | 114 | var row = data.MethodTraceRows.FirstOrDefault(x => x.Id == _row.Id); 115 | if (row is null) 116 | _row.TraceList = new(); 117 | else 118 | _row = row; 119 | RegenRenderLock(); 120 | await InvokeAsync(StateHasChanged); 121 | } 122 | 123 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMemoryModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | @if (_items.Count == 0) 46 | { 47 | 48 | 49 | 50 | } 51 | 52 |
fieldtypeassemblymemorychange
32 | 37 | @item.FieldName@item.TypeName@item.AssemblyName@item.SecondarySnapshotBytes.WvBTToKilobytesString()@((MarkupString)item.ChangeKBHtml)
Memory info is presented only if the current snapshot is selected as secondary
53 |
54 | 57 |
58 | 59 | } 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMemoryModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | using WebVella.BlazorTrace.Utility; 6 | 7 | namespace WebVella.BlazorTrace; 8 | public partial class WvBlazorTraceMemoryModal : WvBlazorTraceComponentBase 9 | { 10 | // INJECTS 11 | ////////////////////////////////////////////////// 12 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 13 | [Inject] public IWvBlazorTraceService WvBlazorTraceService { get; set; } = default!; 14 | 15 | // PARAMETERS 16 | ////////////////////////////////////////////////// 17 | [CascadingParameter(Name = "WvBlazorTraceBody")] 18 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 19 | [Parameter] public int NestLevel { get; set; } = 1; 20 | [Parameter] public EventCallback OnChange { get; set; } 21 | 22 | // LOCAL VARIABLES 23 | ////////////////////////////////////////////////// 24 | private Guid _componentId = Guid.NewGuid(); 25 | private DotNetObjectReference _objectRef = default!; 26 | private bool _escapeListenerEnabled = false; 27 | private bool _modalVisible = false; 28 | private WvMethodTraceRow? _row = null; 29 | private Guid? _traceId = null; 30 | private bool _isOnEnter = true; 31 | private List _items = new(); 32 | private WvBlazorTraceMuteMemoryModal? _memoryMuteModal = null; 33 | 34 | // LIFECYCLE 35 | /// ////////////////////////////////////////////// 36 | public async ValueTask DisposeAsync() 37 | { 38 | if (_escapeListenerEnabled) 39 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 40 | _objectRef?.Dispose(); 41 | } 42 | protected override void OnInitialized() 43 | { 44 | base.OnInitialized(); 45 | _objectRef = DotNetObjectReference.Create(this); 46 | EnableRenderLock(); 47 | } 48 | 49 | // PUBLIC 50 | ////////////////////////////////////////////////// 51 | public async Task Show(WvMethodTraceRow row, Guid? traceId = null, bool isOnEnter = true) 52 | { 53 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 54 | _escapeListenerEnabled = true; 55 | _initData(row, traceId, isOnEnter); 56 | _modalVisible = true; 57 | RegenRenderLock(); 58 | await InvokeAsync(StateHasChanged); 59 | } 60 | public async Task Hide(bool invokeStateChanged = true) 61 | { 62 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 63 | _escapeListenerEnabled = false; 64 | _row = null; 65 | _items = new(); 66 | _modalVisible = false; 67 | RegenRenderLock(); 68 | if (invokeStateChanged) 69 | { 70 | await InvokeAsync(StateHasChanged); 71 | } 72 | } 73 | 74 | [JSInvokable("OnShortcutKey")] 75 | public async Task OnShortcutKey(string code) 76 | { 77 | await Hide(); 78 | } 79 | 80 | 81 | //PRIVATE 82 | ///////////////////////////////////////////////// 83 | private string _getTitle() 84 | { 85 | if (_row is null) return String.Empty; 86 | 87 | var sb = new StringBuilder(); 88 | sb.Append($"{_row.Component}"); 89 | if (!String.IsNullOrWhiteSpace(_row.InstanceTag)) 90 | { 91 | sb.Append($" {_row.InstanceTag}"); 92 | } 93 | sb.Append(""); 94 | sb.Append($"{_row.Method}"); 95 | 96 | return sb.ToString(); 97 | } 98 | 99 | private async Task _onMute(WvSnapshotMemoryComparisonDataField dataField) 100 | { 101 | if (dataField is null || _row is null) return; 102 | if (_memoryMuteModal is null) return; 103 | await _memoryMuteModal.Show(_row, dataField); 104 | } 105 | 106 | private async Task _muteChanged() 107 | { 108 | var data = WvBlazorTraceBody.GetData(); 109 | if (data is null || _row is null) return; 110 | 111 | var row = data.MethodTraceRows.FirstOrDefault(x => x.Id == _row.Id); 112 | _initData(row, _traceId, _isOnEnter); 113 | await OnChange.InvokeAsync(); 114 | RegenRenderLock(); 115 | await InvokeAsync(StateHasChanged); 116 | } 117 | 118 | private void _initData(WvMethodTraceRow? row, Guid? traceId, bool isOnEnter = true) 119 | { 120 | _items = new(); 121 | _traceId = null; 122 | _isOnEnter = true; 123 | if (row is null) return; 124 | 125 | _row = row; 126 | if (traceId is not null) 127 | { 128 | var trace = _row.TraceList.FirstOrDefault(x => x.TraceId == traceId); 129 | if (trace is not null && isOnEnter) 130 | { 131 | _traceId = traceId; 132 | _isOnEnter = isOnEnter; 133 | _items = trace.OnEnterMemoryInfo.ToMemoryDataFields(); 134 | } 135 | else if (trace is not null && !isOnEnter) 136 | { 137 | _traceId = traceId; 138 | _isOnEnter = isOnEnter; 139 | _items = trace.OnExitMemoryInfo.ToMemoryDataFields(); 140 | } 141 | } 142 | else 143 | _items = _row.MemoryComparison.Fields; 144 | } 145 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteLimitModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null && _limitHit is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var item in _applicableTypes) 26 | { 27 | var selected = _selectedTypes.Any(x => x.Id == item.Id); 28 | 29 | 40 | 41 | 48 | 49 | } 50 | @if (_applicableTypes.Count == 0) 51 | { 52 | 53 | 54 | 55 | } 56 | 57 |
scopemuted traces description
30 | @if (selected) 31 | { 32 | 33 | } 34 | else 35 | { 36 | 37 | 38 | } 39 | @((MarkupString)item.Type.WvBTToDescriptionString())@((MarkupString)item.Type.GenerateMuteDescriptionHtml( 42 | module: _row.Module, 43 | component: _row.Component, 44 | instanceTag: _row.InstanceTag, 45 | limitType: _limitHit.Type 46 | )) 47 |
No Custom Data found OnEnter or OnExit in this trace. You need one in order to limit by it.
58 | 59 |
60 | 63 |
64 | } 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteLimitModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceMuteLimitModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | [Parameter] public EventCallback OnChange { get; set; } 19 | 20 | // LOCAL VARIABLES 21 | ////////////////////////////////////////////////// 22 | private Guid _componentId = Guid.NewGuid(); 23 | private DotNetObjectReference _objectRef = default!; 24 | private bool _escapeListenerEnabled = false; 25 | private bool _modalVisible = false; 26 | private WvMethodTraceRow? _row = null; 27 | private WvTraceSessionLimitHit? _limitHit = null; 28 | private List _applicableTypes = new(); 29 | private List _selectedTypes = new(); 30 | 31 | // LIFECYCLE 32 | /// ////////////////////////////////////////////// 33 | public async ValueTask DisposeAsync() 34 | { 35 | if (_escapeListenerEnabled) 36 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 37 | _objectRef?.Dispose(); 38 | } 39 | protected override void OnInitialized() 40 | { 41 | base.OnInitialized(); 42 | _objectRef = DotNetObjectReference.Create(this); 43 | EnableRenderLock(); 44 | } 45 | 46 | protected override void OnParametersSet() 47 | { 48 | base.OnParametersSet(); 49 | RegenRenderLock(); 50 | } 51 | 52 | // PUBLIC 53 | ////////////////////////////////////////////////// 54 | public async Task Show(WvMethodTraceRow row, WvTraceSessionLimitHit dataField) 55 | { 56 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = true; 58 | _row = row; 59 | _limitHit = dataField; 60 | _initMuteOptions(); 61 | _modalVisible = true; 62 | RegenRenderLock(); 63 | await InvokeAsync(StateHasChanged); 64 | } 65 | public async Task Hide(bool invokeStateChanged = true) 66 | { 67 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 68 | _escapeListenerEnabled = false; 69 | _row = null; 70 | _limitHit = null; 71 | _modalVisible = false; 72 | RegenRenderLock(); 73 | if (invokeStateChanged) 74 | { 75 | await InvokeAsync(StateHasChanged); 76 | } 77 | } 78 | 79 | [JSInvokable("OnShortcutKey")] 80 | public async Task OnShortcutKey(string code) 81 | { 82 | await Hide(); 83 | } 84 | 85 | //PRIVATE 86 | ///////////////////////////////////////////////// 87 | private string _getTitle() 88 | { 89 | if (_limitHit is null) return String.Empty; 90 | 91 | var sb = new StringBuilder(); 92 | sb.Append($"Mute method trace"); 93 | 94 | return sb.ToString(); 95 | } 96 | 97 | private async Task _typeClick(WvTraceMute item) 98 | { 99 | await WvBlazorTraceBody.MuteTraceChange(item); 100 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 101 | await OnChange.InvokeAsync(); 102 | RegenRenderLock(); 103 | } 104 | 105 | private void _initMuteOptions() 106 | { 107 | _applicableTypes = new(); 108 | if (_limitHit is not null && _row is not null) 109 | { 110 | _applicableTypes = new(){ 111 | new WvTraceMute(WvTraceMuteType.Limit, _row, _limitHit), 112 | new WvTraceMute(WvTraceMuteType.LimitInModule, _row, _limitHit), 113 | new WvTraceMute(WvTraceMuteType.LimitInComponent, _row, _limitHit), 114 | new WvTraceMute(WvTraceMuteType.LimitInComponentInstance, _row, _limitHit), 115 | }; 116 | } 117 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 118 | } 119 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteMemoryModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null && _dataField is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var item in _applicableTypes) 26 | { 27 | var selected = _selectedTypes.Any(x => x.Id == item.Id); 28 | 29 | 39 | 40 | 47 | 48 | } 49 | 50 |
scopemuted traces description
30 | @if (selected) 31 | { 32 | 33 | } 34 | else 35 | { 36 | 37 | } 38 | @((MarkupString)item.Type.WvBTToDescriptionString())@((MarkupString)item.Type.GenerateMuteDescriptionHtml( 41 | module: _row.Module, 42 | component: _row.Component, 43 | instanceTag: _row.InstanceTag, 44 | field: _dataField.FieldName, 45 | assembly:_dataField.AssemblyName 46 | ))
51 | 52 |
53 | 56 |
57 | } 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteMemoryModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceMuteMemoryModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | [Parameter] public EventCallback OnChange { get; set; } 19 | 20 | // LOCAL VARIABLES 21 | ////////////////////////////////////////////////// 22 | private Guid _componentId = Guid.NewGuid(); 23 | private DotNetObjectReference _objectRef = default!; 24 | private bool _escapeListenerEnabled = false; 25 | private bool _modalVisible = false; 26 | private WvMethodTraceRow? _row = null; 27 | private WvSnapshotMemoryComparisonDataField? _dataField = null; 28 | private List _applicableTypes = new(); 29 | private List _selectedTypes = new(); 30 | 31 | // LIFECYCLE 32 | /// ////////////////////////////////////////////// 33 | public async ValueTask DisposeAsync() 34 | { 35 | if (_escapeListenerEnabled) 36 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 37 | _objectRef?.Dispose(); 38 | } 39 | protected override void OnInitialized() 40 | { 41 | base.OnInitialized(); 42 | _objectRef = DotNetObjectReference.Create(this); 43 | EnableRenderLock(); 44 | } 45 | 46 | protected override void OnParametersSet() 47 | { 48 | base.OnParametersSet(); 49 | RegenRenderLock(); 50 | } 51 | 52 | // PUBLIC 53 | ////////////////////////////////////////////////// 54 | public async Task Show(WvMethodTraceRow row, WvSnapshotMemoryComparisonDataField dataField) 55 | { 56 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = true; 58 | _row = row; 59 | _dataField = dataField; 60 | _initMuteOptions(); 61 | _modalVisible = true; 62 | RegenRenderLock(); 63 | await InvokeAsync(StateHasChanged); 64 | } 65 | public async Task Hide(bool invokeStateChanged = true) 66 | { 67 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 68 | _escapeListenerEnabled = false; 69 | _row = null; 70 | _dataField = null; 71 | _modalVisible = false; 72 | RegenRenderLock(); 73 | if (invokeStateChanged) 74 | { 75 | await InvokeAsync(StateHasChanged); 76 | } 77 | } 78 | 79 | [JSInvokable("OnShortcutKey")] 80 | public async Task OnShortcutKey(string code) 81 | { 82 | await Hide(); 83 | } 84 | 85 | //PRIVATE 86 | ///////////////////////////////////////////////// 87 | private string _getTitle() 88 | { 89 | if (_dataField is null) return String.Empty; 90 | 91 | var sb = new StringBuilder(); 92 | sb.Append($"Mute method trace"); 93 | 94 | return sb.ToString(); 95 | } 96 | 97 | private async Task _typeClick(WvTraceMute item) 98 | { 99 | await WvBlazorTraceBody.MuteTraceChange(item); 100 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 101 | await OnChange.InvokeAsync(); 102 | RegenRenderLock(); 103 | } 104 | 105 | private void _initMuteOptions() 106 | { 107 | _applicableTypes = new(); 108 | if (_dataField is not null && _row is not null) 109 | { 110 | _applicableTypes = new() 111 | { 112 | new WvTraceMute(WvTraceMuteType.Assembly,_row, _dataField), 113 | new WvTraceMute(WvTraceMuteType.Field,_row, _dataField), 114 | new WvTraceMute(WvTraceMuteType.FieldInAssembly,_row, _dataField), 115 | new WvTraceMute(WvTraceMuteType.FieldInModule,_row, _dataField), 116 | new WvTraceMute(WvTraceMuteType.FieldInComponent,_row, _dataField), 117 | new WvTraceMute(WvTraceMuteType.FieldInComponentInstance,_row, _dataField), 118 | }; 119 | } 120 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 121 | } 122 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteMethodModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var item in _applicableTypes) 26 | { 27 | var selected = _selectedTypes.Any(x => x.Id == item.Id); 28 | 29 | 40 | 41 | 47 | 48 | } 49 | 50 |
scopemuted traces description
30 | @if (selected) 31 | { 32 | 33 | } 34 | else 35 | { 36 | 37 | 38 | } 39 | @((MarkupString)item.Type.WvBTToDescriptionString())@((MarkupString)item.Type.GenerateMuteDescriptionHtml( 42 | module:_row.Module, 43 | component:_row.Component, 44 | instanceTag:_row.InstanceTag, 45 | method:_row.Method 46 | ))
51 | 52 |
53 | 56 |
57 | } 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteMethodModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceMuteMethodModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | [Parameter] public EventCallback OnChange { get; set; } 19 | 20 | 21 | // LOCAL VARIABLES 22 | ////////////////////////////////////////////////// 23 | private Guid _componentId = Guid.NewGuid(); 24 | private DotNetObjectReference _objectRef = default!; 25 | private bool _escapeListenerEnabled = false; 26 | private bool _modalVisible = false; 27 | private WvMethodTraceRow? _row = null; 28 | private List _applicableTypes = new(); 29 | private List _selectedTypes = new(); 30 | 31 | // LIFECYCLE 32 | /// ////////////////////////////////////////////// 33 | public async ValueTask DisposeAsync() 34 | { 35 | if (_escapeListenerEnabled) 36 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 37 | _objectRef?.Dispose(); 38 | } 39 | protected override void OnInitialized() 40 | { 41 | base.OnInitialized(); 42 | _objectRef = DotNetObjectReference.Create(this); 43 | EnableRenderLock(); 44 | } 45 | 46 | protected override void OnParametersSet() 47 | { 48 | base.OnParametersSet(); 49 | RegenRenderLock(); 50 | } 51 | 52 | // PUBLIC 53 | ////////////////////////////////////////////////// 54 | public async Task Show(WvMethodTraceRow row) 55 | { 56 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = true; 58 | _row = row; 59 | _initMuteOptions(); 60 | _modalVisible = true; 61 | RegenRenderLock(); 62 | await InvokeAsync(StateHasChanged); 63 | } 64 | public async Task Hide(bool invokeStateChanged = true) 65 | { 66 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 67 | _escapeListenerEnabled = false; 68 | _row = null; 69 | _modalVisible = false; 70 | RegenRenderLock(); 71 | if (invokeStateChanged) 72 | { 73 | await InvokeAsync(StateHasChanged); 74 | } 75 | } 76 | 77 | [JSInvokable("OnShortcutKey")] 78 | public async Task OnShortcutKey(string code) 79 | { 80 | await Hide(); 81 | } 82 | 83 | //PRIVATE 84 | ///////////////////////////////////////////////// 85 | private string _getTitle() 86 | { 87 | if (_row is null) return String.Empty; 88 | 89 | var sb = new StringBuilder(); 90 | sb.Append($"Mute method trace"); 91 | 92 | return sb.ToString(); 93 | } 94 | 95 | private async Task _typeClick(WvTraceMute item) 96 | { 97 | await WvBlazorTraceBody.MuteTraceChange(item); 98 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 99 | await OnChange.InvokeAsync(); 100 | RegenRenderLock(); 101 | } 102 | 103 | private void _initMuteOptions() 104 | { 105 | _applicableTypes = new(); 106 | if (_row is not null) 107 | { 108 | _applicableTypes = new(){ 109 | new WvTraceMute(WvTraceMuteType.MethodInComponentInstance,_row), 110 | new WvTraceMute(WvTraceMuteType.MethodInComponent,_row), 111 | new WvTraceMute(WvTraceMuteType.MethodInModule,_row), 112 | new WvTraceMute(WvTraceMuteType.Method,_row), 113 | new WvTraceMute(WvTraceMuteType.ComponentInstance,_row), 114 | new WvTraceMute(WvTraceMuteType.Component,_row), 115 | new WvTraceMute(WvTraceMuteType.Module,_row), 116 | }; 117 | if (_row!.IsPinned) 118 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.PinnedMethods, _row)); 119 | else 120 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.NotPinnedMethods, _row)); 121 | } 122 | 123 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 124 | } 125 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteSignalModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var item in _applicableTypes) 26 | { 27 | var selected = _selectedTypes.Any(x => x.Id == item.Id); 28 | 29 | 40 | 41 | 42 | 43 | } 44 | 45 |
scopemuted traces description
30 | @if (selected) 31 | { 32 | 33 | } 34 | else 35 | { 36 | 37 | 38 | } 39 | @((MarkupString)item.Type.WvBTToDescriptionString())@((MarkupString)item.Type.GenerateMuteDescriptionHtml(signalName:_row.SignalName))
46 |
47 | 50 |
51 | } 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteSignalModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceMuteSignalModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | 19 | [Parameter] public EventCallback OnChange { get; set; } 20 | 21 | // LOCAL VARIABLES 22 | ////////////////////////////////////////////////// 23 | private Guid _componentId = Guid.NewGuid(); 24 | private DotNetObjectReference _objectRef = default!; 25 | private bool _escapeListenerEnabled = false; 26 | private bool _modalVisible = false; 27 | private WvSignalTraceRow? _row = null; 28 | private List _applicableTypes = new(); 29 | private List _selectedTypes = new(); 30 | 31 | // LIFECYCLE 32 | /// ////////////////////////////////////////////// 33 | public async ValueTask DisposeAsync() 34 | { 35 | if (_escapeListenerEnabled) 36 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 37 | _objectRef?.Dispose(); 38 | } 39 | protected override void OnInitialized() 40 | { 41 | base.OnInitialized(); 42 | _objectRef = DotNetObjectReference.Create(this); 43 | EnableRenderLock(); 44 | } 45 | 46 | protected override void OnParametersSet() 47 | { 48 | base.OnParametersSet(); 49 | RegenRenderLock(); 50 | } 51 | 52 | // PUBLIC 53 | ////////////////////////////////////////////////// 54 | public async Task Show(WvSignalTraceRow row) 55 | { 56 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = true; 58 | _row = row; 59 | _initMuteOptions(); 60 | _modalVisible = true; 61 | RegenRenderLock(); 62 | await InvokeAsync(StateHasChanged); 63 | } 64 | public async Task Hide(bool invokeStateChanged = true) 65 | { 66 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 67 | _escapeListenerEnabled = false; 68 | _row = null; 69 | _modalVisible = false; 70 | RegenRenderLock(); 71 | if (invokeStateChanged) 72 | { 73 | await InvokeAsync(StateHasChanged); 74 | } 75 | } 76 | 77 | [JSInvokable("OnShortcutKey")] 78 | public async Task OnShortcutKey(string code) 79 | { 80 | await Hide(); 81 | } 82 | 83 | //PRIVATE 84 | ///////////////////////////////////////////////// 85 | private string _getTitle() 86 | { 87 | if (_row is null) return String.Empty; 88 | 89 | var sb = new StringBuilder(); 90 | sb.Append($"Mute signal"); 91 | 92 | return sb.ToString(); 93 | } 94 | 95 | private async Task _typeClick(WvTraceMute item) 96 | { 97 | await WvBlazorTraceBody.MuteTraceChange(item); 98 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 99 | await OnChange.InvokeAsync(); 100 | RegenRenderLock(); 101 | } 102 | 103 | private void _initMuteOptions() 104 | { 105 | _applicableTypes = new(); 106 | if (_row is not null) 107 | { 108 | _applicableTypes = new(){ 109 | new WvTraceMute(WvTraceMuteType.Signal,_row), 110 | }; 111 | if (_row!.IsPinned) 112 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.PinnedSignals, _row)); 113 | else 114 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.NotPinnedSignals, _row)); 115 | } 116 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 117 | } 118 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteSignalTraceModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null && _signalTrace is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var item in _applicableTypes) 26 | { 27 | var selected = _selectedTypes.Any(x => x.Id == item.Id); 28 | 29 | 40 | 41 | 49 | 50 | } 51 | 52 |
scopemuted traces description
30 | @if (selected) 31 | { 32 | 33 | } 34 | else 35 | { 36 | 37 | 38 | } 39 | @((MarkupString)item.Type.WvBTToDescriptionString()) 42 | @((MarkupString)item.Type.GenerateMuteDescriptionHtml( 43 | module: _signalTrace.ModuleName, 44 | component: _signalTrace.ComponentName, 45 | instanceTag: _signalTrace.InstanceTag, 46 | signalName: _row.SignalName 47 | )) 48 |
53 | 54 |
55 | 58 |
59 | } 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteSignalTraceModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceMuteSignalTraceModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | [Parameter] public EventCallback OnChange { get; set; } 19 | 20 | // LOCAL VARIABLES 21 | ////////////////////////////////////////////////// 22 | private Guid _componentId = Guid.NewGuid(); 23 | private DotNetObjectReference _objectRef = default!; 24 | private bool _escapeListenerEnabled = false; 25 | private bool _modalVisible = false; 26 | private WvSignalTraceRow? _row = null; 27 | private WvTraceSessionSignalTrace? _signalTrace = null; 28 | private List _applicableTypes = new(); 29 | private List _selectedTypes = new(); 30 | 31 | // LIFECYCLE 32 | /// ////////////////////////////////////////////// 33 | public async ValueTask DisposeAsync() 34 | { 35 | if (_escapeListenerEnabled) 36 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 37 | _objectRef?.Dispose(); 38 | } 39 | protected override void OnInitialized() 40 | { 41 | base.OnInitialized(); 42 | _objectRef = DotNetObjectReference.Create(this); 43 | EnableRenderLock(); 44 | } 45 | 46 | protected override void OnParametersSet() 47 | { 48 | base.OnParametersSet(); 49 | RegenRenderLock(); 50 | } 51 | 52 | // PUBLIC 53 | ////////////////////////////////////////////////// 54 | public async Task Show(WvSignalTraceRow row, WvTraceSessionSignalTrace dataField) 55 | { 56 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = true; 58 | _row = row; 59 | _signalTrace = dataField; 60 | _initMuteOptions(); 61 | _modalVisible = true; 62 | RegenRenderLock(); 63 | await InvokeAsync(StateHasChanged); 64 | } 65 | public async Task Hide(bool invokeStateChanged = true) 66 | { 67 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 68 | _escapeListenerEnabled = false; 69 | _row = null; 70 | _signalTrace = null; 71 | _modalVisible = false; 72 | RegenRenderLock(); 73 | if (invokeStateChanged) 74 | { 75 | await InvokeAsync(StateHasChanged); 76 | } 77 | } 78 | 79 | [JSInvokable("OnShortcutKey")] 80 | public async Task OnShortcutKey(string code) 81 | { 82 | await Hide(); 83 | } 84 | 85 | //PRIVATE 86 | ///////////////////////////////////////////////// 87 | private string _getTitle() 88 | { 89 | if (_signalTrace is null) return String.Empty; 90 | 91 | var sb = new StringBuilder(); 92 | sb.Append($"Mute method trace"); 93 | 94 | return sb.ToString(); 95 | } 96 | 97 | private async Task _typeClick(WvTraceMute item) 98 | { 99 | await WvBlazorTraceBody.MuteTraceChange(item); 100 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 101 | await OnChange.InvokeAsync(); 102 | RegenRenderLock(); 103 | } 104 | 105 | private void _initMuteOptions() 106 | { 107 | _applicableTypes = new(); 108 | if (_signalTrace is not null && _row is not null) 109 | { 110 | _applicableTypes = new(){ 111 | new WvTraceMute(WvTraceMuteType.SignalInModule,_row,_signalTrace), 112 | new WvTraceMute(WvTraceMuteType.SignalInComponent,_row,_signalTrace), 113 | new WvTraceMute(WvTraceMuteType.SignalInComponentInstance,_row,_signalTrace), 114 | }; 115 | 116 | } 117 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 118 | } 119 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteTraceModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null && _methodTrace is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var item in _applicableTypes) 26 | { 27 | var selected = _selectedTypes.Any(x => x.Id == item.Id); 28 | 29 | 40 | 41 | 49 | 50 | } 51 | @if (_applicableTypes.Count == 0) 52 | { 53 | 54 | 55 | 56 | } 57 | 58 |
scopemuted traces description
30 | @if (selected) 31 | { 32 | 33 | } 34 | else 35 | { 36 | 37 | 38 | } 39 | @((MarkupString)item.Type.WvBTToDescriptionString())@((MarkupString)item.Type.GenerateMuteDescriptionHtml( 42 | module: _row.Module, 43 | component: _row.Component, 44 | instanceTag: _row.InstanceTag, 45 | onEnterCustomData: _methodTrace.OnEnterCustomData, 46 | onExitCustomData: _methodTrace.OnExitCustomData 47 | )) 48 |
No Custom Data found OnEnter or OnExit in this trace. You need one in order to limit by it.
59 | 60 |
61 | 64 |
65 | } 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceMuteTraceModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceMuteTraceModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [CascadingParameter(Name = "WvBlazorTraceBody")] 16 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 17 | [Parameter] public int NestLevel { get; set; } = 1; 18 | [Parameter] public EventCallback OnChange { get; set; } 19 | 20 | // LOCAL VARIABLES 21 | ////////////////////////////////////////////////// 22 | private Guid _componentId = Guid.NewGuid(); 23 | private DotNetObjectReference _objectRef = default!; 24 | private bool _escapeListenerEnabled = false; 25 | private bool _modalVisible = false; 26 | private WvMethodTraceRow? _row = null; 27 | private WvTraceSessionMethodTrace? _methodTrace = null; 28 | private List _applicableTypes = new(); 29 | private List _selectedTypes = new(); 30 | 31 | // LIFECYCLE 32 | /// ////////////////////////////////////////////// 33 | public async ValueTask DisposeAsync() 34 | { 35 | if (_escapeListenerEnabled) 36 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 37 | _objectRef?.Dispose(); 38 | } 39 | protected override void OnInitialized() 40 | { 41 | base.OnInitialized(); 42 | _objectRef = DotNetObjectReference.Create(this); 43 | EnableRenderLock(); 44 | } 45 | 46 | protected override void OnParametersSet() 47 | { 48 | base.OnParametersSet(); 49 | RegenRenderLock(); 50 | } 51 | 52 | // PUBLIC 53 | ////////////////////////////////////////////////// 54 | public async Task Show(WvMethodTraceRow row, WvTraceSessionMethodTrace dataField) 55 | { 56 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 57 | _escapeListenerEnabled = true; 58 | _row = row; 59 | _methodTrace = dataField; 60 | _initMuteOptions(); 61 | _modalVisible = true; 62 | RegenRenderLock(); 63 | await InvokeAsync(StateHasChanged); 64 | } 65 | public async Task Hide(bool invokeStateChanged = true) 66 | { 67 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 68 | _escapeListenerEnabled = false; 69 | _row = null; 70 | _methodTrace = null; 71 | _modalVisible = false; 72 | RegenRenderLock(); 73 | if (invokeStateChanged) 74 | { 75 | await InvokeAsync(StateHasChanged); 76 | } 77 | } 78 | 79 | [JSInvokable("OnShortcutKey")] 80 | public async Task OnShortcutKey(string code) 81 | { 82 | await Hide(); 83 | } 84 | 85 | //PRIVATE 86 | ///////////////////////////////////////////////// 87 | private string _getTitle() 88 | { 89 | if (_methodTrace is null) return String.Empty; 90 | 91 | var sb = new StringBuilder(); 92 | sb.Append($"Mute method trace"); 93 | 94 | return sb.ToString(); 95 | } 96 | 97 | private async Task _typeClick(WvTraceMute item) 98 | { 99 | await WvBlazorTraceBody.MuteTraceChange(item); 100 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 101 | await OnChange.InvokeAsync(); 102 | RegenRenderLock(); 103 | } 104 | 105 | private void _initMuteOptions() 106 | { 107 | _applicableTypes = new(); 108 | if (_methodTrace is not null && _row is not null) 109 | { 110 | _applicableTypes = new(); 111 | if (!String.IsNullOrWhiteSpace(_methodTrace.OnEnterCustomData)) 112 | { 113 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnEnterCustomData, _row, _methodTrace.OnEnterCustomData)); 114 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnEnterCustomDataInModule, _row, _methodTrace.OnEnterCustomData)); 115 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnEnterCustomDataInComponent, _row, _methodTrace.OnEnterCustomData)); 116 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnEnterCustomDataInComponentInstance, _row, _methodTrace.OnEnterCustomData)); 117 | } 118 | if (!String.IsNullOrWhiteSpace(_methodTrace.OnExitCustomData)) 119 | { 120 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnExitCustomData, _row, _methodTrace.OnExitCustomData)); 121 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnExitCustomDataInModule, _row, _methodTrace.OnExitCustomData)); 122 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnExitCustomDataInComponent, _row, _methodTrace.OnExitCustomData)); 123 | _applicableTypes.Add(new WvTraceMute(WvTraceMuteType.OnExitCustomDataInComponentInstance, _row, _methodTrace.OnExitCustomData)); 124 | } 125 | 126 | } 127 | _selectedTypes = WvBlazorTraceBody.GetTraceMutes(); 128 | } 129 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceSignalLimitModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_modalVisible && _row is not null) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | @if (_row.LimitHits.Count == 0) 34 | { 35 | 36 | 37 | 38 | } 39 | 40 |
limit typelimitactual
@item.Type.WvBTToDescriptionString()@item.Limit.GetLimitValueAsString(item.Type)@item.Actual.GetLimitValueAsString(item.Type)
No tracers are logged yet for this method
41 |
42 | 45 |
46 | } 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceSignalLimitModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceSignalLimitModal : WvBlazorTraceComponentBase 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | [Parameter] public int NestLevel { get; set; } = 1; 16 | 17 | // LOCAL VARIABLES 18 | ////////////////////////////////////////////////// 19 | private Guid _componentId = Guid.NewGuid(); 20 | private DotNetObjectReference _objectRef = default!; 21 | private bool _escapeListenerEnabled = false; 22 | private bool _modalVisible = false; 23 | private WvSignalTraceRow? _row = null; 24 | 25 | // LIFECYCLE 26 | /// ////////////////////////////////////////////// 27 | public async ValueTask DisposeAsync() 28 | { 29 | if (_escapeListenerEnabled) 30 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 31 | _objectRef?.Dispose(); 32 | } 33 | protected override void OnInitialized() 34 | { 35 | base.OnInitialized(); 36 | _objectRef = DotNetObjectReference.Create(this); 37 | EnableRenderLock(); 38 | } 39 | 40 | // PUBLIC 41 | ////////////////////////////////////////////////// 42 | public async Task Show(WvSignalTraceRow row) 43 | { 44 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 45 | _escapeListenerEnabled = true; 46 | _row = row; 47 | _modalVisible = true; 48 | RegenRenderLock(); 49 | await InvokeAsync(StateHasChanged); 50 | } 51 | public async Task Hide(bool invokeStateChanged = true) 52 | { 53 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 54 | _escapeListenerEnabled = false; 55 | _row = null; 56 | _modalVisible = false; 57 | RegenRenderLock(); 58 | if (invokeStateChanged) 59 | { 60 | await InvokeAsync(StateHasChanged); 61 | } 62 | } 63 | 64 | [JSInvokable("OnShortcutKey")] 65 | public async Task OnShortcutKey(string code) 66 | { 67 | await Hide(); 68 | } 69 | 70 | //PRIVATE 71 | ///////////////////////////////////////////////// 72 | private string _getTitle() 73 | { 74 | if (_row is null) return String.Empty; 75 | 76 | var sb = new StringBuilder(); 77 | sb.Append($"{_row.SignalName}"); 78 | 79 | return sb.ToString(); 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceSignalTraceListModal.razor: -------------------------------------------------------------------------------- 1 | @namespace WebVella.BlazorTrace 2 | @using WebVella.BlazorTrace.Utility 3 | @inherits WvBlazorTraceComponentBase 4 | @if (_row is not null && _modalVisible) 5 | { 6 | var style = $"z-index:{(20000 + (2 * NestLevel))}"; 7 | 8 |
9 |
10 |
@((MarkupString)_getTitle())
11 |
12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 39 | 40 | 41 | 49 | 50 | 51 | 54 | 55 | 56 | @if (_row.TraceList.Count == 0) 57 | { 58 | 59 | 60 | 61 | } 62 | 63 |
send onmodulecomponentmethodcustom datalimits
33 | 38 | @item.SendOn.ToString("yyyy-MMM-dd HH:mm:ss")@item.ModuleName 42 | @item.ComponentName 43 | @if (!String.IsNullOrWhiteSpace(item.InstanceTag)) 44 | { 45 | 46 | @item.InstanceTag 47 | } 48 | @item.MethodName@item.CustomData 52 | 53 |
No tracers are logged yet for this method
64 |
65 | 68 |
69 | 70 | 71 | } 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/WvBlazorTraceSignalTraceListModal.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System.Text; 4 | using WebVella.BlazorTrace.Models; 5 | 6 | namespace WebVella.BlazorTrace; 7 | public partial class WvBlazorTraceSignalTraceListModal : WvBlazorTraceComponentBase, IAsyncDisposable 8 | { 9 | // INJECTS 10 | ////////////////////////////////////////////////// 11 | [Inject] protected IJSRuntime JSRuntimeSrv { get; set; } = default!; 12 | 13 | // PARAMETERS 14 | ////////////////////////////////////////////////// 15 | 16 | [CascadingParameter(Name = "WvBlazorTraceBody")] 17 | public WvBlazorTraceBody WvBlazorTraceBody { get; set; } = default!; 18 | [Parameter] public int NestLevel { get; set; } = 1; 19 | 20 | // LOCAL VARIABLES 21 | ////////////////////////////////////////////////// 22 | private Guid _componentId = Guid.NewGuid(); 23 | private DotNetObjectReference _objectRef = default!; 24 | private bool _escapeListenerEnabled = false; 25 | private bool _modalVisible = false; 26 | private WvSignalTraceRow? _row = null; 27 | private WvBlazorTraceLimitInfoSignalModal? _limitInfoModal = null; 28 | private WvBlazorTraceMuteSignalTraceModal? _traceMuteModal = null; 29 | // LIFECYCLE 30 | /// ////////////////////////////////////////////// 31 | public async ValueTask DisposeAsync() 32 | { 33 | if (_escapeListenerEnabled) 34 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 35 | _objectRef?.Dispose(); 36 | } 37 | protected override void OnInitialized() 38 | { 39 | base.OnInitialized(); 40 | _objectRef = DotNetObjectReference.Create(this); 41 | EnableRenderLock(); 42 | } 43 | 44 | // PUBLIC 45 | ////////////////////////////////////////////////// 46 | public async Task Show(WvSignalTraceRow row) 47 | { 48 | await new JsService(JSRuntimeSrv).AddKeyEventListener(_objectRef, "OnShortcutKey", "Escape", _componentId.ToString()); 49 | _escapeListenerEnabled = true; 50 | _row = row; 51 | _modalVisible = true; 52 | RegenRenderLock(); 53 | await InvokeAsync(StateHasChanged); 54 | } 55 | public async Task Hide(bool invokeStateChanged = true) 56 | { 57 | await new JsService(JSRuntimeSrv).RemoveKeyEventListener("Escape", _componentId.ToString()); 58 | _escapeListenerEnabled = false; 59 | _row = null; 60 | _modalVisible = false; 61 | RegenRenderLock(); 62 | if (invokeStateChanged) 63 | { 64 | await InvokeAsync(StateHasChanged); 65 | } 66 | } 67 | 68 | [JSInvokable("OnShortcutKey")] 69 | public async Task OnShortcutKey(string code) 70 | { 71 | await Hide(); 72 | } 73 | 74 | //PRIVATE 75 | ///////////////////////////////////////////////// 76 | private string _getTitle() 77 | { 78 | if (_row is null) return String.Empty; 79 | 80 | var sb = new StringBuilder(); 81 | sb.Append($"{_row.SignalName}"); 82 | 83 | return sb.ToString(); 84 | } 85 | private async Task _showLimitInfoModal(WvTraceSessionSignalTrace trace, bool isOnEnter = true) 86 | { 87 | if (_limitInfoModal is null) return; 88 | await _limitInfoModal.Show(trace.Options); 89 | } 90 | 91 | private async Task _onMute(WvTraceSessionSignalTrace dataField) 92 | { 93 | if (dataField is null || _row is null) return; 94 | if (_traceMuteModal is null) return; 95 | await _traceMuteModal.Show(_row, dataField); 96 | } 97 | 98 | private async Task _muteChanged() 99 | { 100 | var data = WvBlazorTraceBody.GetData(); 101 | if (data is null || _row is null) return; 102 | 103 | var row = data.SignalTraceRows.FirstOrDefault(x => x.Id == _row.Id); 104 | if (row is null) 105 | _row.TraceList = new(); 106 | else 107 | _row = row; 108 | RegenRenderLock(); 109 | await InvokeAsync(StateHasChanged); 110 | } 111 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Components/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.JSInterop 8 | @using WebVella.BlazorTrace.Components 9 | @using WebVella.BlazorTrace.Models 10 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvBlazorTraceComponentBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public class WvBlazorTraceComponentBase : ComponentBase 10 | { 11 | public bool IsRenderLockEnabled { get; private set; } = false; 12 | public Guid CurrentRenderLock { get; private set; } = Guid.Empty; 13 | public Guid OldRenderLock { get; private set; } = Guid.Empty; 14 | 15 | protected void EnableRenderLock() => IsRenderLockEnabled = true; 16 | protected void DisableRenderLock() => IsRenderLockEnabled = false; 17 | protected void RegenRenderLock() => CurrentRenderLock = Guid.NewGuid(); 18 | protected override void OnParametersSet() 19 | { 20 | if (IsRenderLockEnabled) RegenRenderLock(); 21 | } 22 | 23 | protected override bool ShouldRender() 24 | { 25 | if (!IsRenderLockEnabled) return true; 26 | if (CurrentRenderLock == OldRenderLock) return false; 27 | OldRenderLock = CurrentRenderLock; 28 | return true; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvBlazorTraceConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using WebVella.BlazorTrace.Models; 3 | 4 | namespace WebVella.BlazorTrace; 5 | public class WvBlazorTraceConfiguration 6 | { 7 | /// 8 | /// By default the tracing is enabled, but from this property you can stop the tracing globally 9 | /// 10 | public bool EnableTracing { get; set; } = true; 11 | 12 | /// 13 | /// For easier tool development 14 | /// 15 | public bool AutoShowModal { get; set; } = false; 16 | 17 | /// 18 | /// By default F1 will open the trace modal 19 | /// 20 | public bool EnableF1Shortcut { get; set; } = true; 21 | 22 | /// 23 | /// Assemblies name start strings that you want to always include in memory trace. 24 | /// 25 | public List MemoryIncludeAssemblyList { get; set; } = new(); 26 | 27 | /// 28 | /// Assemblies name start strings that you want to exclude from memory trace. 29 | /// Some framework assemblies are excluded by default. Set the to false if you need them 30 | /// 31 | public List MemoryExcludeAssemblyList { get; set; } = new(); 32 | 33 | /// 34 | /// By default some framework assemblies are excluded for convenience. 35 | /// 36 | public bool ExcludeDefaultAssemblies { get; set; } = true; 37 | 38 | /// 39 | /// Field Names that are containing one of the strings in this list will be always included in the trace 40 | /// 41 | public List MemoryIncludeFieldNameList { get; set; } = new(); 42 | 43 | /// 44 | /// Field Names that are containing one of the strings in this list will be excluded from the trace 45 | /// Some field names are excluded by default. Set the to false if you need them 46 | /// 47 | public List MemoryExcludeFieldNameList { get; set; } = new(); 48 | 49 | /// 50 | /// By default some field names that are excluded for convenience. 51 | /// 52 | public bool ExcludeDefaultFieldNames { get; set; } = true; 53 | 54 | /// 55 | /// Override the default Trace method options 56 | /// 57 | public WvTraceMethodOptions? DefaultTraceMethodOptions { get; set; } = null; 58 | 59 | /// 60 | /// Override the default Trace signal options 61 | /// 62 | public WvTraceSignalOptions? DefaultTraceSignalOptions { get; set; } = null; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvButtonPosition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public enum WvButtonPosition 10 | { 11 | [Description("wv-trace-hidden")] 12 | Hidden = 0, 13 | [Description("wv-trace-right-top")] 14 | RightTop = 1, 15 | [Description("wv-trace-right-center")] 16 | RightCenter = 2, 17 | [Description("wv-trace-right-bottom")] 18 | RightBottom = 3, 19 | [Description("wv-trace-bottom-right")] 20 | BottomRight = 4, 21 | [Description("wv-trace-bottom-center")] 22 | BottomCenter = 5, 23 | [Description("wv-trace-bottom-left")] 24 | BottomLeft = 6, 25 | [Description("wv-trace-left-top")] 26 | LeftTop = 7, 27 | [Description("wv-trace-left-center")] 28 | LeftCenter = 8, 29 | [Description("wv-trace-left-bottom")] 30 | LeftBottom = 9, 31 | [Description("wv-trace-top-left")] 32 | TopLeft = 10, 33 | [Description("wv-trace-top-center")] 34 | TopCenter = 11, 35 | [Description("wv-trace-top-right")] 36 | TopRight = 12 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvCall.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public class WvCall 10 | { 11 | public DateTimeOffset? EnteredOn { get; set; } 12 | public DateTimeOffset? ExitedOn { get; set; } 13 | [JsonIgnore] 14 | public long DurationMs 15 | { 16 | get 17 | { 18 | if (EnteredOn is null || ExitedOn is null) return 0; 19 | if(EnteredOn.Value > ExitedOn.Value) return 0; 20 | return (ExitedOn.Value - EnteredOn.Value).Milliseconds; 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvLocalStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public class WvLocalStore 10 | { 11 | public List Pins { get; set; } = new(); 12 | public List MutedTraces { get; set; } = new(); 13 | public WvTraceModalRequest? LastModalRequest { get; set; } = null; 14 | public List Snapshots { get; set; } = new(); 15 | } 16 | 17 | public class WvSnapshotStore 18 | { 19 | public Guid Id { get; set; } = Guid.NewGuid(); 20 | public DateTimeOffset CreatedOn { get; set; } = default!; 21 | public string Name { get; set; } = string.Empty; 22 | public string? CompressedModuleDict { get; set; } = null; 23 | public string? CompressedSignalDict { get; set; } = null; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSignalTraceRow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | using WebVella.BlazorTrace.Utility; 8 | 9 | namespace WebVella.BlazorTrace.Models; 10 | public class WvSignalTraceRow 11 | { 12 | [JsonIgnore] 13 | public string Id { get => WvModalUtility.GenerateSignalHash(SignalName); } 14 | public string? SignalName { get; set; } 15 | public bool IsPinned { get; set; } = false; 16 | public List TraceList { get; set; } = new(); 17 | public List LimitHits { get; set; } = new(); 18 | [JsonIgnore] 19 | public string LimitsHint 20 | { 21 | get 22 | { 23 | var hints = new List(); 24 | if (LimitHits.Count > 0) hints.Add($"{LimitHits.Count} calls"); 25 | 26 | if (hints.Count == 0) return "no limits are hit"; 27 | 28 | return String.Join("; ", hints); 29 | } 30 | } 31 | [JsonIgnore] 32 | public string LimitsHtml 33 | { 34 | get 35 | { 36 | var html = new List(); 37 | if (LimitHits.Count > 0) 38 | html.Add($"{LimitHits.Count}"); 39 | else 40 | html.Add($"0"); 41 | 42 | return String.Join(" / ", html); 43 | } 44 | } 45 | public WvSnapshotSignalComparisonData SignalComparison { get; set; } = new(); 46 | public bool SignalNameMatches(string? search) 47 | { 48 | 49 | if (string.IsNullOrWhiteSpace(search)) return true; 50 | 51 | if ((SignalName ?? String.Empty).ToLowerInvariant().Contains(search.Trim().ToLowerInvariant())) 52 | return true; 53 | 54 | return false; 55 | } 56 | 57 | public bool CallsMatches(WvTraceModalCallsFilter? filter) 58 | { 59 | if (filter is null) return true; 60 | if (TraceList is null) return false; 61 | 62 | if (filter == WvTraceModalCallsFilter.LessThan25 && TraceList.Count <= 25) return true; 63 | if (filter == WvTraceModalCallsFilter.TwentyFiveTo50 && TraceList.Count > 25 && TraceList.Count <= 50) return true; 64 | if (filter == WvTraceModalCallsFilter.MoreThan50 && TraceList.Count > 50) return true; 65 | if (filter == WvTraceModalCallsFilter.PositiveDelta && SignalComparison.TraceListChange > 0) return true; 66 | if (filter == WvTraceModalCallsFilter.NegativeDelta && SignalComparison.TraceListChange < 0) return true; 67 | if (filter == WvTraceModalCallsFilter.NoDelta && SignalComparison.TraceListChange == 0) return true; 68 | 69 | return false; 70 | } 71 | 72 | 73 | public bool LimitMatches(WvTraceModalLimitsFilter? filter) 74 | { 75 | if (filter is null) return true; 76 | if (LimitHits is null) return false; 77 | if (filter == WvTraceModalLimitsFilter.HasLimitHits && LimitHits.Count > 0) return true; 78 | if (filter == WvTraceModalLimitsFilter.ZeroLimitHits && LimitHits.Count == 0) return true; 79 | if (filter == WvTraceModalLimitsFilter.ExceedCallLimit && LimitHits.Count > 0) return true; 80 | 81 | return false; 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public class WvSnapshot 10 | { 11 | public Guid Id { get; set; } = Guid.NewGuid(); 12 | public DateTimeOffset CreatedOn { get; set; } = default!; 13 | public string Name { get; set; } = string.Empty; 14 | public Dictionary ModuleDict { get; set; } = new(); 15 | public Dictionary SignalDict { get; set; } = new(); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSnapshotListItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebVella.BlazorTrace.Models; 8 | public class WvSnapshotListItem 9 | { 10 | public Guid Id { get; set; } 11 | public string Name { get; set; } = default!; 12 | public DateTimeOffset CreatedOn { get; set; } = default!; 13 | public Action OnRemove { get; set; } = default!; 14 | public Action OnRename { get; set; } = default!; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSnapshotMemoryComparison.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | using WebVella.BlazorTrace.Utility; 8 | 9 | namespace WebVella.BlazorTrace.Models; 10 | public class WvSnapshotMemoryComparison 11 | { 12 | public WvTraceSessionMethod PrimarySnapshotMethod { get; set; } = default!; 13 | public WvTraceSessionMethod SecondarySnapshotMethod { get; set; } = default!; 14 | public WvSnapshotMemoryComparisonData ComparisonData { get; set; } = new(); 15 | } 16 | 17 | public class WvSnapshotMemoryComparisonData 18 | { 19 | public long LastMemoryChangeBytes { get; set; } 20 | [JsonIgnore] 21 | public string LastMemoryChangeKBHtml 22 | { 23 | get 24 | { 25 | if (LastMemoryChangeBytes == 0) return $"="; 26 | else if (LastMemoryChangeBytes < 0) 27 | { 28 | return $"{LastMemoryChangeBytes.WvBTToKilobytesString()}"; 29 | } 30 | return $"+{LastMemoryChangeBytes.WvBTToKilobytesString()}"; 31 | } 32 | } 33 | public List Fields { get; set; } = new(); 34 | } 35 | 36 | 37 | public class WvSnapshotMemoryComparisonDataField 38 | { 39 | [JsonIgnore] 40 | public string Id { get => WvTraceUtility.WvBTGetMemoryInfoId(AssemblyName, FieldName); } 41 | public string FieldName { get; set; } = String.Empty; 42 | public string TypeName { get; set; } = String.Empty; 43 | public string AssemblyName { get; set; } = String.Empty; 44 | public long? PrimarySnapshotBytes { get; set; } 45 | public long? SecondarySnapshotBytes { get; set; } 46 | [JsonIgnore] 47 | public long ChangeBytes => (SecondarySnapshotBytes ?? 0) - (PrimarySnapshotBytes ?? 0); 48 | [JsonIgnore] 49 | public string ChangeKBHtml 50 | { 51 | get 52 | { 53 | if (ChangeBytes == 0) return $"="; 54 | else if (ChangeBytes < 0) 55 | { 56 | return $"{ChangeBytes.WvBTToKilobytesString()}"; 57 | } 58 | return $"+{ChangeBytes.WvBTToKilobytesString()}"; 59 | } 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSnapshotMethodComparison.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | using WebVella.BlazorTrace.Utility; 8 | 9 | namespace WebVella.BlazorTrace.Models; 10 | public class WvSnapshotMethodComparison 11 | { 12 | public WvTraceSessionMethod PrimarySnapshotMethod { get; set; } = default!; 13 | public WvTraceSessionMethod SecondarySnapshotMethod { get; set; } = default!; 14 | public WvSnapshotMethodComparisonData ComparisonData { get; set; } = new(); 15 | } 16 | 17 | public class WvSnapshotMethodComparisonData 18 | { 19 | public int TraceListChange { get; set; } 20 | [JsonIgnore] 21 | public string TraceListChangeHtml 22 | { 23 | get 24 | { 25 | if (TraceListChange == 0) return $"="; 26 | else if (TraceListChange < 0) 27 | { 28 | return $"{TraceListChange}"; 29 | } 30 | return $"+{TraceListChange}"; 31 | } 32 | } 33 | public long LastDurationChangeMS { get; set; } 34 | [JsonIgnore] 35 | public string LastDurationChangeMSHtml 36 | { 37 | get 38 | { 39 | if (LastDurationChangeMS == 0) return $"="; 40 | else if (LastDurationChangeMS < 0) 41 | { 42 | return $"{LastDurationChangeMS}"; 43 | } 44 | return $"+{LastDurationChangeMS}"; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSnapshotSavingState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebVella.BlazorTrace.Models; 8 | public enum WvSnapshotSavingState 9 | { 10 | NotSaving = 0, 11 | Saving = 1, 12 | Saved = 2 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvSnapshotSignalComparison.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | using WebVella.BlazorTrace.Utility; 8 | 9 | namespace WebVella.BlazorTrace.Models; 10 | public class WvSnapshotSignalComparison 11 | { 12 | public WvTraceSessionSignal PrimarySnapshotSignal { get; set; } = default!; 13 | public WvTraceSessionSignal SecondarySnapshotSignal { get; set; } = default!; 14 | public WvSnapshotSignalComparisonData ComparisonData { get; set; } = new(); 15 | } 16 | 17 | public class WvSnapshotSignalComparisonData 18 | { 19 | public int TraceListChange { get; set; } 20 | [JsonIgnore] 21 | public string TraceListChangeHtml 22 | { 23 | get 24 | { 25 | if (TraceListChange == 0) return $"="; 26 | else if (TraceListChange < 0) 27 | { 28 | return $"{TraceListChange}"; 29 | } 30 | return $"+{TraceListChange}"; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public class WvTraceInfo 10 | { 11 | public Guid? TraceId { get; set; } 12 | public string? MethodName { get; set; } 13 | public string? ComponentFullName { get; set; } 14 | public string? ComponentName { get; set; } 15 | public string? InstanceTag { get; set; } 16 | public string? ModuleName { get; set; } 17 | [JsonIgnore] 18 | public bool CanGetMemory { get => IsOnAfterRender; } 19 | [JsonIgnore] 20 | public bool IsOnInitialized { get => new List {"OnInitialized","OnInitializedAsync"}.Contains(MethodName ?? string.Empty); } 21 | [JsonIgnore] 22 | public bool IsOnParameterSet { get => new List {"OnParametersSet","OnParametersSetAsync"}.Contains(MethodName ?? string.Empty); } 23 | [JsonIgnore] 24 | public bool IsOnAfterRender { get => new List {"OnAfterRender","OnAfterRenderAsync"}.Contains(MethodName ?? string.Empty); } 25 | [JsonIgnore] 26 | public bool IsShouldRender { get => new List {"ShouldRender"}.Contains(MethodName ?? string.Empty); } 27 | [JsonIgnore] 28 | public bool IsDispose { get => new List {"Dispose","DisposeAsync"}.Contains(MethodName ?? string.Empty); } 29 | [JsonIgnore] 30 | public bool IsOther { get => !IsOnInitialized && !IsOnParameterSet && !IsOnAfterRender && !IsShouldRender && !IsDispose; } 31 | } 32 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceMemoryInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | using WebVella.BlazorTrace.Utility; 8 | 9 | namespace WebVella.BlazorTrace.Models; 10 | public class WvTraceMemoryInfo 11 | { 12 | [JsonIgnore] 13 | public string Id { get => WvTraceUtility.WvBTGetMemoryInfoId(AssemblyName,FieldName); } 14 | public string FieldName { get; set; } = String.Empty; 15 | public string TypeName { get; set; } = String.Empty; 16 | public string AssemblyName { get; set; } = String.Empty; 17 | public long Size { get; set; } = 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceMethodOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebVella.BlazorTrace.Models; 8 | public class WvTraceMethodOptions 9 | { 10 | /// 11 | /// How many milliseconds is an OK for executing this method. Default is 1000. 12 | /// 13 | public long DurationLimitMS { get; set; } = 1000; 14 | 15 | /// 16 | /// How many calls is OK for this method. Default is 10. 17 | /// 18 | public long CallLimit { get; set; } = 10; 19 | 20 | /// 21 | /// What is the total maximum memory limit. Default is 2048. 22 | /// 23 | public long MemoryLimitTotalBytes { get; set; } = 2048; 24 | 25 | /// 26 | /// What is the maximum memory delta limit between enter and exit. Default is 2048. 27 | /// 28 | public long MemoryLimitDeltaBytes { get; set; } = 2048; 29 | } 30 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceModalMenuItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public class WvTraceModalMenuItem 10 | { 11 | public WvTraceModalMenu Id { get; set; } = WvTraceModalMenu.MethodName; 12 | public bool IsActive { get; set; } = false; 13 | public int Counter { get; set; } = 0; 14 | [JsonIgnore] 15 | public string CounterHtml 16 | { 17 | get 18 | { 19 | if (Counter <= 0) return String.Empty; 20 | return $"{(Counter > 99 ? "99+" : Counter)}"; 21 | } 22 | } 23 | [JsonIgnore] 24 | public Action OnClick { get; set; } = default!; 25 | } 26 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceMuteType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebVella.BlazorTrace.Models; 9 | public enum WvTraceMuteType 10 | { 11 | [Description("Module")] 12 | Module = 0, 13 | [Description("Component")] 14 | Component = 1, 15 | [Description("Component Instance")] 16 | ComponentInstance = 2, 17 | [Description("Method")] 18 | Method = 10, 19 | [Description("Method in Module")] 20 | MethodInModule = 11, 21 | [Description("Method in Component")] 22 | MethodInComponent = 12, 23 | [Description("Method in Component Instance")] 24 | MethodInComponentInstance = 13, 25 | [Description("Signal")] 26 | Signal = 20, 27 | [Description("Signal in Module")] 28 | SignalInModule = 21, 29 | [Description("Signal in Component")] 30 | SignalInComponent = 22, 31 | [Description("Signal in Component Instance")] 32 | SignalInComponentInstance = 23, 33 | [Description("Field")] 34 | Field = 30, 35 | [Description("Field in Module")] 36 | FieldInModule = 31, 37 | [Description("Field in Component")] 38 | FieldInComponent = 32, 39 | [Description("Field in Component Instance")] 40 | FieldInComponentInstance = 33, 41 | [Description("Field in Assembly")] 42 | FieldInAssembly = 34, 43 | [Description("Assembly")] 44 | Assembly = 35, 45 | [Description("Limit")] 46 | Limit = 40, 47 | [Description("Limit in Module")] 48 | LimitInModule = 41, 49 | [Description("Limit in Component")] 50 | LimitInComponent = 42, 51 | [Description("Limit in Component Instance")] 52 | LimitInComponentInstance = 43, 53 | [Description("OnEnter Custom Data")] 54 | OnEnterCustomData = 50, 55 | [Description("OnEnter Custom Data in Module")] 56 | OnEnterCustomDataInModule = 51, 57 | [Description("OnEnter Custom Data in Component")] 58 | OnEnterCustomDataInComponent = 52, 59 | [Description("OnEnter Custom Data in Component Instance")] 60 | OnEnterCustomDataInComponentInstance = 53, 61 | [Description("OnExit Custom Data")] 62 | OnExitCustomData = 54, 63 | [Description("OnExit Custom Data in Module")] 64 | OnExitCustomDataInModule = 55, 65 | [Description("OnExit Custom Data in Component")] 66 | OnExitCustomDataInComponent = 56, 67 | [Description("OnExit Custom Data in Component Instance")] 68 | OnExitCustomDataInComponentInstance = 57, 69 | [Description("Not Pinned methods")] 70 | NotPinnedMethods = 60, 71 | [Description("Pinned methods")] 72 | PinnedMethods = 61, 73 | [Description("Not Pinned signals")] 74 | NotPinnedSignals = 62, 75 | [Description("Pinned signals")] 76 | PinnedSignals = 63, 77 | } 78 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceQueueAction.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.Json.Serialization; 7 | using System.Threading.Tasks; 8 | using WebVella.BlazorTrace.Utility; 9 | 10 | namespace WebVella.BlazorTrace.Models; 11 | public class WvTraceQueueAction 12 | { 13 | public WvTraceQueueItemMethod MethodCalled { get; set; } = WvTraceQueueItemMethod.OnEnter; 14 | [JsonIgnore] 15 | public object Caller { get; set; } = default!; 16 | public Guid? TraceId { get; set; } = null; 17 | public WvTraceMethodOptions MethodOptions { get; set; } = default!; 18 | public WvTraceSignalOptions SignalOptions { get; set; } = default!; 19 | public bool? FirstRender { get; set; } = null; 20 | public string SignalName { get; set; } = default!; 21 | public string? InstanceTag { get; set; } = null; 22 | public string? CustomData { get; set; } = null; 23 | public string MethodName { get; set; } = default!; 24 | public DateTimeOffset Timestamp { get; set; } = default!; 25 | } 26 | 27 | public enum WvTraceQueueItemMethod 28 | { 29 | OnEnter = 0, 30 | OnExit = 1, 31 | Signal = 2 32 | } 33 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceSession.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.Json.Serialization; 8 | using System.Threading.Tasks; 9 | using WebVella.BlazorTrace.Utility; 10 | 11 | namespace WebVella.BlazorTrace.Models; 12 | public class WvTraceSessionModule 13 | { 14 | public Dictionary ComponentDict { get; set; } = new(); 15 | } 16 | 17 | public class WvTraceSessionComponent 18 | { 19 | public string? Name { get; set; } 20 | public List TaggedInstances { get; set; } = new(); 21 | } 22 | 23 | public class WvTraceSessionComponentTaggedInstance 24 | { 25 | public string? Tag { get; set; } 26 | public WvTraceSessionMethod OnInitialized { get; set; } = new(); 27 | public WvTraceSessionMethod OnParameterSet { get; set; } = new(); 28 | public WvTraceSessionMethod OnAfterRender { get; set; } = new(); 29 | public WvTraceSessionMethod ShouldRender { get; set; } = new(); 30 | public WvTraceSessionMethod Dispose { get; set; } = new(); 31 | public List OtherMethods { get; set; } = new(); 32 | 33 | public List MethodsTotal() 34 | { 35 | var methods = new List(); 36 | methods.Add(OnInitialized); 37 | methods.Add(OnParameterSet); 38 | methods.Add(OnAfterRender); 39 | methods.Add(ShouldRender); 40 | methods.Add(Dispose); 41 | methods.AddRange(OtherMethods); 42 | var calledMethods = new List(); 43 | foreach (var method in methods) 44 | { 45 | if (method.MaxCallsCount > 0) 46 | calledMethods.Add(method); 47 | } 48 | return calledMethods; 49 | } 50 | } 51 | 52 | public class WvTraceSessionMethod 53 | { 54 | public string? Name { get; set; } = null; 55 | public List TraceList { get; set; } = new(); 56 | //Generated props 57 | [JsonIgnore] 58 | public long? MinDurationMs { get => this.GetMinDuration(); } 59 | [JsonIgnore] 60 | public long? MaxDurationMs { get => this.GetMaxDuration(); } 61 | [JsonIgnore] 62 | public long? LastDurationMS { get => this.GetLastDuration(); } 63 | [JsonIgnore] 64 | public long? OnEnterMinMemoryBytes { get => this.GetMinMemory(isOnEnter: true); } 65 | [JsonIgnore] 66 | public long? OnEnterMaxMemoryBytes { get => this.GetMaxMemory(isOnEnter: true); } 67 | [JsonIgnore] 68 | public long? OnExitMinMemoryBytes { get => this.GetMinMemory(isOnEnter: false); } 69 | [JsonIgnore] 70 | public long? OnExitMaxMemoryBytes { get => this.GetMaxMemory(isOnEnter: false); } 71 | [JsonIgnore] 72 | public long? LastMemoryBytes { get => this.GetLastMemory().Item1; } 73 | [JsonIgnore] 74 | public List? LastMemoryInfo { get => this.GetLastMemory().Item2; } 75 | [JsonIgnore] 76 | public long? MinMemoryDeltaBytes { get => this.GetMinMemoryDelta(); } 77 | [JsonIgnore] 78 | public long? MaxMemoryDeltaBytes { get => this.GetMaxMemoryDelta(); } 79 | [JsonIgnore] 80 | public long OnEnterCallsCount { get => this.GetOnEnterCallCount(); } 81 | [JsonIgnore] 82 | public long OnExitCallsCount { get => this.GetOnExitCallsCount(); } 83 | [JsonIgnore] 84 | public long MaxCallsCount { get => this.GetMaxCallsCount(); } 85 | [JsonIgnore] 86 | public long CompletedCallsCount { get => this.CompletedCallsCount(); } 87 | [JsonIgnore] 88 | public WvTraceSessionMethodTrace? LastExitedTrace 89 | { 90 | get => TraceList.Where(x => x.ExitedOn is not null).OrderByDescending(x => x.ExitedOn).FirstOrDefault(); 91 | } 92 | [JsonIgnore] 93 | public List LimitHits { get => this.CalculateLimitsInfo(); } 94 | public string GenerateHash(string moduleName, string componentFullname, string? tag) 95 | { 96 | return WvModalUtility.GenerateMethodHash(moduleName, componentFullname, tag, Name); 97 | } 98 | } 99 | 100 | 101 | public class WvTraceSessionMethodTrace 102 | { 103 | public Guid TraceId { get; set; } = default!; 104 | public DateTimeOffset? EnteredOn { get; set; } = null; 105 | public DateTimeOffset? ExitedOn { get; set; } = null; 106 | public long? OnEnterMemoryBytes { get; set; } = null; 107 | public long? OnExitMemoryBytes { get; set; } = null; 108 | public bool? OnEnterFirstRender { get; set; } = null; 109 | public bool? OnExitFirstRender { get; set; } = null; 110 | public string? OnEnterCustomData { get; set; } = null; 111 | public string? OnExitCustomData { get; set; } = null; 112 | public WvTraceMethodOptions OnEnterOptions { get; set; } = new(); 113 | public WvTraceMethodOptions OnExitOptions { get; set; } = new(); 114 | 115 | //Non Serializable - to much info to be stored in the store JSON 116 | [JsonIgnore] 117 | public List? OnEnterMemoryInfo { get; set; } = null; 118 | 119 | [JsonIgnore] 120 | public List? OnExitMemoryInfo { get; set; } = null; 121 | 122 | //Generated props 123 | [JsonIgnore] 124 | public long? DurationMs { get => this.GetDurationMS(); } 125 | [JsonIgnore] 126 | public string OnEnterLimitsHTML { get => this.CalculateLimitsHTML(true); } 127 | [JsonIgnore] 128 | public string OnExitLimitsHTML { get => this.CalculateLimitsHTML(false); } 129 | } 130 | 131 | public class WvTraceSessionSignal 132 | { 133 | public List TraceList { get; set; } = new(); 134 | 135 | [JsonIgnore] 136 | public List LimitHits { get => this.CalculateLimitsInfo(); } 137 | } 138 | 139 | public class WvTraceSessionSignalTrace 140 | { 141 | public DateTimeOffset SendOn { get; set; } = default!; 142 | public string? ModuleName { get; set; } = null; 143 | public string? ComponentName { get; set; } = null; 144 | public string? ComponentFullName { get; set; } = null; 145 | public string? InstanceTag { get; set; } = null; 146 | public string? MethodName { get; set; } = null; 147 | public string? CustomData { get; set; } = null; 148 | public WvTraceSignalOptions Options { get; set; } = default!; 149 | } 150 | 151 | 152 | public class WvTraceSessionLimitHit 153 | { 154 | public bool IsOnEnter { get; set; } = true; 155 | public WvTraceSessionLimitType Type { get; set; } 156 | public long Limit { get; set; } = 0; 157 | public long Actual { get; set; } = 0; 158 | } 159 | 160 | public enum WvTraceSessionLimitType 161 | { 162 | [Description("calls count")] 163 | CallCount = 0, 164 | [Description("duration")] 165 | Duration = 1, 166 | [Description("total memory")] 167 | MemoryTotal = 2, 168 | [Description("memory delta")] 169 | MemoryDelta = 3 170 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvTraceSignalOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebVella.BlazorTrace.Models; 8 | public class WvTraceSignalOptions 9 | { 10 | /// 11 | /// How many calls is OK for this method. Default is 10. 12 | /// 13 | public long CallLimit { get; set; } = 10; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Models/WvUnionData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebVella.BlazorTrace.Models; 8 | public class WvModuleUnionData 9 | { 10 | public WvTraceSessionModule? Primary { get; set; } 11 | public WvTraceSessionModule? Secondary { get; set; } 12 | public Dictionary ComponentDict { get; set; } = new(); 13 | public Dictionary SignalDict { get; set; } = new(); 14 | } 15 | 16 | 17 | public class WvComponentUnionData 18 | { 19 | public string? Name { get; set; } 20 | public WvTraceSessionComponent? Primary { get; set; } 21 | public WvTraceSessionComponent? Secondary { get; set; } 22 | public List TaggedInstances { get; set; } = new(); 23 | } 24 | 25 | public class WvSignalUnionData 26 | { 27 | public WvTraceSessionSignal? Primary { get; set; } 28 | public WvTraceSessionSignal? Secondary { get; set; } 29 | } 30 | 31 | public class WvTaggedInstanceUnionData 32 | { 33 | public string? Tag { get; set; } 34 | public WvTraceSessionComponentTaggedInstance? Primary { get; set; } 35 | public WvTraceSessionComponentTaggedInstance? Secondary { get; set; } 36 | public Dictionary MethodDict { get; set; } = new(); 37 | } 38 | 39 | public class WvMethodUnionData 40 | { 41 | public WvTraceSessionMethod? Primary { get; set; } 42 | public WvTraceSessionMethod? Secondary { get; set; } 43 | 44 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Services/JsService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.JSInterop; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WebVella.BlazorTrace.Models; 8 | 9 | namespace WebVella.BlazorTrace; 10 | public class JsService 11 | { 12 | protected IJSRuntime JSRuntime { get; } 13 | public JsService(IJSRuntime jsRuntime) 14 | { 15 | JSRuntime = jsRuntime; 16 | } 17 | public async ValueTask AddKeyEventListener(object objectRef, string methodName, string keyCode, string? listenerId = null) 18 | { 19 | try 20 | { 21 | if (keyCode == "Escape") 22 | return await JSRuntime.InvokeAsync( 23 | "WebVellaBlazorTrace.addEscapeKeyEventListener", 24 | objectRef, listenerId, methodName); 25 | else if (keyCode == "F1") 26 | return await JSRuntime.InvokeAsync( 27 | "WebVellaBlazorTrace.addF1KeyEventListener", 28 | objectRef, methodName); 29 | } 30 | catch 31 | { 32 | } 33 | return false; 34 | } 35 | 36 | public async ValueTask RemoveKeyEventListener(string keyCode, string? listenerId = null) 37 | { 38 | try 39 | { 40 | if (keyCode == "Escape") 41 | return await JSRuntime.InvokeAsync( 42 | "WebVellaBlazorTrace.removeEscapeKeyEventListener", listenerId); 43 | else if (keyCode == "F1") 44 | return await JSRuntime.InvokeAsync( 45 | "WebVellaBlazorTrace.removeF1KeyEventListener"); 46 | } 47 | catch 48 | { 49 | } 50 | return false; 51 | } 52 | 53 | public async Task SetUnprotectedLocalStorageAsync(string key, string value) 54 | { 55 | await JSRuntime.InvokeVoidAsync("localStorage.setItem", key, value); 56 | } 57 | 58 | public async Task RemoveUnprotectedLocalStorageAsync(string key) 59 | { 60 | await JSRuntime.InvokeVoidAsync("localStorage.removeItem", key); 61 | } 62 | 63 | public async Task GetUnprotectedLocalStorageAsync(string key) 64 | { 65 | return await JSRuntime.InvokeAsync("localStorage.getItem", key); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Services/WvBlazorTraceConfigurationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Net.WebSockets; 8 | using System.Reflection; 9 | using System.Runtime.CompilerServices; 10 | using System.Runtime.InteropServices; 11 | using System.Text; 12 | using System.Text.Json; 13 | using System.Text.Json.Serialization; 14 | using System.Threading.Tasks; 15 | using WebVella.BlazorTrace.Models; 16 | using WebVella.BlazorTrace.Utility; 17 | 18 | namespace WebVella.BlazorTrace; 19 | public partial interface IWvBlazorTraceConfigurationService 20 | { 21 | WvBlazorTraceConfiguration GetConfiguraion(); 22 | } 23 | public partial class WvBlazorTraceConfigurationService : IWvBlazorTraceConfigurationService 24 | { 25 | private readonly WvBlazorTraceConfiguration _configuration = default!; 26 | public WvBlazorTraceConfigurationService(WvBlazorTraceConfiguration? config) 27 | { 28 | this._configuration = config is not null ? config : new(); 29 | if (_configuration.ExcludeDefaultAssemblies) 30 | { 31 | if (_configuration.MemoryExcludeAssemblyList is null) 32 | _configuration.MemoryExcludeAssemblyList = new(); 33 | 34 | _configuration.MemoryExcludeAssemblyList.AddRange( 35 | new[]{ 36 | "Microsoft.AspNetCore" 37 | } 38 | ); 39 | } 40 | if (_configuration.ExcludeDefaultFieldNames) 41 | { 42 | if (_configuration.MemoryExcludeFieldNameList is null) 43 | _configuration.MemoryExcludeFieldNameList = new(); 44 | 45 | _configuration.MemoryExcludeFieldNameList.AddRange( 46 | new[]{ 47 | "k__BackingField" 48 | } 49 | ); 50 | } 51 | if(_configuration.DefaultTraceMethodOptions is null) 52 | _configuration.DefaultTraceMethodOptions = new(); 53 | 54 | if(_configuration.DefaultTraceSignalOptions is null) 55 | _configuration.DefaultTraceSignalOptions = new(); 56 | } 57 | public WvBlazorTraceConfiguration GetConfiguraion() 58 | { 59 | return _configuration; 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Services/WvBlazorTraceInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.JSInterop; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using WebVella.BlazorTrace.Models; 9 | 10 | namespace WebVella.BlazorTrace; 11 | public static class WvBlazorTraceInjection 12 | { 13 | public static IServiceCollection AddBlazorTrace(this IServiceCollection services, 14 | WvBlazorTraceConfiguration? configuration = null) 15 | { 16 | services.AddSingleton(provider => new WvBlazorTraceConfigurationService(configuration)); 17 | services.AddScoped(); 18 | return services; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Services/WvBlazorTraceService.Queue.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Net.WebSockets; 9 | using System.Reflection; 10 | using System.Runtime.CompilerServices; 11 | using System.Runtime.InteropServices; 12 | using System.Text; 13 | using System.Text.Json; 14 | using System.Text.Json.Serialization; 15 | using System.Threading.Tasks; 16 | using WebVella.BlazorTrace.Models; 17 | using WebVella.BlazorTrace.Utility; 18 | 19 | namespace WebVella.BlazorTrace; 20 | public partial interface IWvBlazorTraceService 21 | { 22 | ConcurrentQueue GetQueue(); 23 | void ForceProcessQueue(); 24 | } 25 | public partial class WvBlazorTraceService : IWvBlazorTraceService 26 | { 27 | public ConcurrentQueue GetQueue() => _traceQueue; 28 | // Because of the force process the queue process could be triggered from two methods 29 | public Lock _queueProcessLock = LockFactory.Create(); 30 | private void _addToQueue(WvTraceQueueAction trace) 31 | { 32 | _traceQueue.Enqueue(trace); 33 | } 34 | private void _processQueue() 35 | { 36 | _infiniteLoopCancellationTokenSource = new CancellationTokenSource(); 37 | _infiniteLoop = Task.Run(async () => 38 | { 39 | //Just to be sure that local trace mutes are loaded 40 | _ = await GetTraceMutes(); 41 | while (!_infiniteLoopCancellationTokenSource.IsCancellationRequested) 42 | { 43 | await Task.Delay(_infiniteLoopDelaySeconds * 1000); 44 | lock (_queueProcessLock) 45 | { 46 | while (!_traceQueue.IsEmpty) 47 | { 48 | try 49 | { 50 | if (_traceQueue.TryDequeue(out var trace)) 51 | { 52 | _processQueueTrace(trace); 53 | } 54 | } 55 | catch (Exception ex) 56 | { 57 | Console.Error.WriteLine(ex.Message.ToString() + Environment.NewLine + ex.StackTrace); 58 | break; 59 | } 60 | } 61 | } 62 | 63 | } 64 | }, _infiniteLoopCancellationTokenSource.Token); 65 | } 66 | private void _processQueueTrace(WvTraceQueueAction action) 67 | { 68 | if (action is null) return; 69 | if (action.Caller is null) return; 70 | var traceInfo = action.Caller.GetInfo(action.TraceId, action.InstanceTag, action.MethodName); 71 | if (traceInfo is null) 72 | throw new Exception("callerInfo cannot be evaluated"); 73 | _saveSessionTrace(traceInfo, action); 74 | } 75 | 76 | public void ForceProcessQueue() 77 | { 78 | lock (_queueProcessLock) 79 | { 80 | while (!_traceQueue.IsEmpty) 81 | { 82 | try 83 | { 84 | if (_traceQueue.TryDequeue(out var trace)) 85 | { 86 | _processQueueTrace(trace); 87 | } 88 | } 89 | catch (Exception ex) 90 | { 91 | Console.Error.WriteLine(ex.Message.ToString() + Environment.NewLine + ex.StackTrace); 92 | break; 93 | } 94 | } 95 | } 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Services/WvBlazorTraceService.Signals.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.JSInterop; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Net.WebSockets; 8 | using System.Reflection; 9 | using System.Runtime.CompilerServices; 10 | using System.Runtime.InteropServices; 11 | using System.Text; 12 | using System.Text.Json; 13 | using System.Text.Json.Serialization; 14 | using System.Threading.Tasks; 15 | using WebVella.BlazorTrace.Models; 16 | using WebVella.BlazorTrace.Utility; 17 | 18 | namespace WebVella.BlazorTrace; 19 | public partial interface IWvBlazorTraceService 20 | { 21 | 22 | } 23 | public partial class WvBlazorTraceService : IWvBlazorTraceService 24 | { 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Services/WvBlazorTraceService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.JSInterop; 4 | using System; 5 | using System.Collections.Concurrent; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Linq; 9 | using System.Net.WebSockets; 10 | using System.Reflection; 11 | using System.Runtime.CompilerServices; 12 | using System.Runtime.InteropServices; 13 | using System.Text; 14 | using System.Text.Json; 15 | using System.Text.Json.Serialization; 16 | using System.Threading.Tasks; 17 | using WebVella.BlazorTrace.Models; 18 | using WebVella.BlazorTrace.Utility; 19 | 20 | namespace WebVella.BlazorTrace; 21 | public partial interface IWvBlazorTraceService 22 | { 23 | Dictionary GetModuleDict(); 24 | Dictionary GetSignalDict(); 25 | void ClearCurrentSession(); 26 | Task> GetTraceMutes(); 27 | } 28 | public partial class WvBlazorTraceService : IWvBlazorTraceService, IDisposable 29 | { 30 | private static IServiceProvider _serviceProvider; 31 | private IJSRuntime _jSRuntime; 32 | private const string _snapshotStoreKey = "wvbtstore"; 33 | private Dictionary _moduleDictInternal = new(); 34 | private Dictionary _signalDictInternal = new(); 35 | private List? _traceMutesInternal = null; 36 | private WvBlazorTraceConfiguration _configuration = new(); 37 | private readonly ConcurrentQueue _traceQueue = new(); 38 | private int _infiniteLoopDelaySeconds = 1; 39 | private Task? _infiniteLoop; 40 | private CancellationTokenSource? _infiniteLoopCancellationTokenSource; 41 | 42 | 43 | /// 44 | /// Needs to be implemented to destroy the infinite loop 45 | /// 46 | /// 47 | public void Dispose() 48 | { 49 | if (_infiniteLoopCancellationTokenSource is not null) 50 | _infiniteLoopCancellationTokenSource.Cancel(); 51 | } 52 | 53 | public WvBlazorTraceService(IJSRuntime jSRuntime, 54 | IWvBlazorTraceConfigurationService configurationService, 55 | IServiceProvider serviceProvider, 56 | bool triggerQueueProcessing = true) 57 | { 58 | _serviceProvider = serviceProvider; 59 | this._jSRuntime = jSRuntime; 60 | this._configuration = configurationService.GetConfiguraion(); 61 | if (triggerQueueProcessing) 62 | _processQueue(); 63 | } 64 | 65 | public Dictionary GetModuleDict() 66 | { 67 | return _moduleDictInternal.Clone(); 68 | } 69 | 70 | public Dictionary GetSignalDict() 71 | { 72 | return _signalDictInternal.Clone(); 73 | } 74 | 75 | public async Task> GetTraceMutes() 76 | { 77 | if (_traceMutesInternal is null) 78 | { 79 | var store = await GetLocalStoreAsync(); 80 | _traceMutesInternal = store.MutedTraces ?? new(); 81 | } 82 | return _traceMutesInternal.Clone(); 83 | } 84 | public void ClearCurrentSession() 85 | { 86 | _moduleDictInternal = new(); 87 | _signalDictInternal = new(); 88 | } 89 | 90 | internal static IWvBlazorTraceService? GetScopedService() 91 | { 92 | if (_serviceProvider is null) 93 | return null; 94 | 95 | var service = _serviceProvider.GetRequiredService(); 96 | return service; 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Styles/index.less: -------------------------------------------------------------------------------- 1 | @import 'wv-trace-button.less'; 2 | @import 'wv-trace-modal.less'; 3 | @import 'wv-trace-nav.less'; 4 | 5 | .animation-keyframes(@name, @from, @to, @anim-selector) { 6 | @keyf: ~"@keyframes @{name} { `'\n'`from "; 7 | @anim: ~"} `'\n'`.@{anim-selector}"; 8 | 9 | @{keyf} { 10 | .from(@name,@from); 11 | } 12 | 13 | to { 14 | .to(@name,@to); 15 | } 16 | 17 | @{anim} { 18 | animation-name: @name; 19 | } 20 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Styles/wv-trace-button.less: -------------------------------------------------------------------------------- 1 | .wv-trace-button { 2 | position: fixed; 3 | z-index: 19000; 4 | @button-offset: 50px; 5 | @button-size: 36px; 6 | @button-center-offset: calc(@button-size / -2); 7 | 8 | button { 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | width: @button-size; 13 | height: @button-size; 14 | /*background: #e11d48;*/ 15 | color: white; 16 | border: 1px solid transparent; 17 | box-shadow: 0 0 10px rgba(0,0,0,0.25); 18 | 19 | &:hover { 20 | cursor: pointer; 21 | box-shadow: 0 0 10px rgba(0,0,0,0.5); 22 | } 23 | 24 | svg { 25 | width: 20px; 26 | height: 20px; 27 | position: relative; 28 | } 29 | } 30 | 31 | &.wv-trace-right-top { 32 | right: 0; 33 | top: @button-offset; 34 | } 35 | 36 | &.wv-trace-right-center { 37 | right: 0; 38 | top: 50%; 39 | margin-top: @button-center-offset; 40 | } 41 | 42 | &.wv-trace-right-bottom { 43 | right: 0; 44 | bottom: @button-offset; 45 | } 46 | 47 | &.wv-trace-right-top, 48 | &.wv-trace-right-center, 49 | &.wv-trace-right-bottom { 50 | button { 51 | border-radius: 50% 0 0 50%; 52 | 53 | svg { 54 | top: 1px; 55 | } 56 | } 57 | } 58 | 59 | &.wv-trace-bottom-right { 60 | bottom: 0; 61 | right: @button-offset; 62 | } 63 | 64 | &.wv-trace-bottom-center { 65 | bottom: 0; 66 | left: 50%; 67 | margin-left: @button-center-offset; 68 | } 69 | 70 | &.wv-trace-bottom-left { 71 | bottom: 0; 72 | left: @button-offset; 73 | } 74 | 75 | &.wv-trace-bottom-right, 76 | &.wv-trace-bottom-center, 77 | &.wv-trace-bottom-left { 78 | button { 79 | border-radius: 50% 50% 0 0; 80 | 81 | svg { 82 | top: 1px; 83 | } 84 | } 85 | } 86 | 87 | 88 | &.wv-trace-left-bottom { 89 | left: 0; 90 | bottom: @button-offset; 91 | } 92 | 93 | &.wv-trace-left-center { 94 | left: 0; 95 | top: 50%; 96 | margin-top: @button-center-offset; 97 | } 98 | 99 | &.wv-trace-left-top { 100 | left: 0; 101 | top: @button-offset; 102 | } 103 | 104 | &.wv-trace-left-bottom, 105 | &.wv-trace-left-center, 106 | &.wv-trace-left-top { 107 | button { 108 | border-radius: 0 50% 50% 0; 109 | 110 | svg { 111 | top: 1px; 112 | } 113 | } 114 | } 115 | 116 | 117 | &.wv-trace-top-left { 118 | top: 0; 119 | left: @button-offset; 120 | } 121 | 122 | &.wv-trace-top-center { 123 | top: 0; 124 | left: 50%; 125 | margin-left: @button-center-offset; 126 | } 127 | 128 | &.wv-trace-top-right { 129 | top: 0; 130 | right: @button-offset; 131 | } 132 | 133 | &.wv-trace-top-left, 134 | &.wv-trace-top-center, 135 | &.wv-trace-top-right { 136 | button { 137 | border-radius: 0 0 50% 50%; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Styles/wv-trace-nav.less: -------------------------------------------------------------------------------- 1 | .wv-trace-nav { 2 | list-style-type: none; 3 | margin: 0; 4 | padding: 0; 5 | overflow: hidden; 6 | @color-accent: #be123c; 7 | 8 | li { 9 | float: left; 10 | 11 | & > a, & > span { 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | text-align: center; 16 | padding: 0 7px; 17 | text-decoration: none; 18 | 19 | .wv-badge { 20 | margin-left: 5px; 21 | display: inline-flex; 22 | padding: 0px 5px; 23 | background: @color-accent; 24 | color: white; 25 | font-size: 11px; 26 | border-radius: 5px; 27 | } 28 | 29 | svg { 30 | margin-left: 5px; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/TraceView.razor: -------------------------------------------------------------------------------- 1 | 
2 | This component is defined in the WebVella.BlazorTrace library. 3 |
4 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Utility/CompressionUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using System.Text; 5 | 6 | namespace WebVella.BlazorTrace; 7 | /// 8 | /// Provides utility methods for compressing and decompressing strings, 9 | /// particularly useful for JSON strings to reduce their size for storage or transmission. 10 | /// 11 | public static class CompressionUtility 12 | { 13 | /// 14 | /// Compresses a given string using GZip compression and returns the compressed data as a Base64 string. 15 | /// This is useful for reducing the size of JSON strings before storing or sending them. 16 | /// 17 | /// The original string (e.g., a JSON string) to compress. 18 | /// A Base64 encoded string representing the compressed data. 19 | /// Thrown if the input string is null. 20 | public static string CompressString(this string jsonString) 21 | { 22 | if (jsonString == null) 23 | { 24 | throw new ArgumentNullException(nameof(jsonString), "The string to compress cannot be null."); 25 | } 26 | 27 | // Convert the string to a byte array using UTF-8 encoding 28 | byte[] originalBytes = Encoding.UTF8.GetBytes(jsonString); 29 | 30 | using (MemoryStream memoryStream = new MemoryStream()) 31 | { 32 | // Create a GZipStream to compress the data and write it to the memory stream 33 | using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) 34 | { 35 | gzipStream.Write(originalBytes, 0, originalBytes.Length); 36 | } // The GZipStream is closed here, which flushes its buffer to the underlying MemoryStream 37 | 38 | // Get the compressed byte array from the memory stream 39 | byte[] compressedBytes = memoryStream.ToArray(); 40 | 41 | // Convert the compressed byte array to a Base64 string for easy storage/transmission 42 | return Convert.ToBase64String(compressedBytes); 43 | } 44 | } 45 | 46 | /// 47 | /// Decompresses a Base64 encoded string that was previously compressed using GZip, 48 | /// and returns the original string (e.g., the original JSON string). 49 | /// 50 | /// The Base64 encoded compressed string to decompress. 51 | /// The original decompressed string. 52 | /// Thrown if the input string is null. 53 | /// Thrown if the input string is not a valid Base64 string. 54 | public static string DecompressString(this string compressedString) 55 | { 56 | if (compressedString == null) 57 | { 58 | throw new ArgumentNullException(nameof(compressedString), "The string to decompress cannot be null."); 59 | } 60 | 61 | // Convert the Base64 string back to a byte array 62 | byte[] compressedBytes = Convert.FromBase64String(compressedString); 63 | 64 | using (MemoryStream memoryStream = new MemoryStream(compressedBytes)) 65 | { 66 | // Create a GZipStream to decompress the data from the memory stream 67 | using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) 68 | { 69 | // Create a new MemoryStream to hold the decompressed data 70 | using (MemoryStream decompressedStream = new MemoryStream()) 71 | { 72 | // Copy the decompressed bytes from the GZipStream to the decompressedStream 73 | gzipStream.CopyTo(decompressedStream); 74 | 75 | // Get the decompressed byte array 76 | byte[] decompressedBytes = decompressedStream.ToArray(); 77 | 78 | // Convert the decompressed byte array back to a string using UTF-8 encoding 79 | return Encoding.UTF8.GetString(decompressedBytes); 80 | } 81 | } 82 | } 83 | } 84 | 85 | // Example Usage (for demonstration purposes, typically in a separate Main method or test) 86 | public static void Main(string[] args) 87 | { 88 | string originalJson = "{\"name\": \"John Doe\", \"age\": 30, \"city\": \"New York\", \"occupation\": \"Software Engineer\", \"hobbies\": [\"reading\", \"hiking\", \"coding\"], \"address\": {\"street\": \"123 Main St\", \"zip\": \"10001\"}}"; 89 | 90 | Console.WriteLine("Original JSON String Length: " + originalJson.Length); 91 | Console.WriteLine("Original JSON String: " + originalJson); 92 | 93 | // Compress the string 94 | string compressedBase64 = CompressString(originalJson); 95 | Console.WriteLine("\nCompressed (Base64) String Length: " + compressedBase64.Length); 96 | Console.WriteLine("Compressed (Base64) String: " + compressedBase64); 97 | 98 | // Decompress the string 99 | string decompressedJson = DecompressString(compressedBase64); 100 | Console.WriteLine("\nDecompressed JSON String Length: " + decompressedJson.Length); 101 | Console.WriteLine("Decompressed JSON String: " + decompressedJson); 102 | 103 | // Verify if the decompressed string is identical to the original 104 | bool areEqual = originalJson.Equals(decompressedJson); 105 | Console.WriteLine("\nOriginal and Decompressed strings are equal: " + areEqual); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Utility/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Globalization; 3 | using WebVella.BlazorTrace.Models; 4 | 5 | namespace WebVella.BlazorTrace; 6 | 7 | public static class EnumExtensions 8 | { 9 | public static string WvBTToDescriptionString(this TEnum e) where TEnum : IConvertible 10 | { 11 | string description = ""; 12 | 13 | if (e is Enum) 14 | { 15 | Type type = e.GetType(); 16 | var name = type.GetEnumName(e.ToInt32(CultureInfo.InvariantCulture)); 17 | if (String.IsNullOrWhiteSpace(name)) return description; 18 | 19 | var memInfo = type.GetMember(name); 20 | var soAttributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); 21 | if (soAttributes.Length > 0) 22 | { 23 | // we're only getting the first description we find 24 | // others will be ignored 25 | description = ((DescriptionAttribute)soAttributes[0]).Description; 26 | } 27 | } 28 | 29 | return description; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Utility/WvTraceUtility.Converters.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.Serialization; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using WebVella.BlazorTrace.Models; 11 | 12 | namespace WebVella.BlazorTrace.Utility; 13 | public static partial class WvTraceUtility 14 | { 15 | public static string WvBTToKilobytesString(this long? bytes) 16 | { 17 | if (bytes == null) return "n/a"; 18 | 19 | if (bytes < 0) return "err"; // Handle invalid input 20 | if (bytes == 0) return "0 KB"; 21 | if (bytes <= 15) return bytes.ToString() + " bytes"; 22 | const double kilobyteFactor = 1024.0; 23 | var kb = Math.Round((double)bytes / kilobyteFactor, 2, MidpointRounding.AwayFromZero); 24 | return kb.ToString() + " KB"; 25 | } 26 | public static string WvBTToKilobytesString(this long bytes) 27 | { 28 | if (bytes < 0) return "err"; // Handle invalid input 29 | if (bytes == 0) return "0 KB"; 30 | if (bytes <= 15) return bytes.ToString() + " bytes"; 31 | const double kilobyteFactor = 1024.0; 32 | var kb = Math.Round((double)bytes / kilobyteFactor, 2, MidpointRounding.AwayFromZero); 33 | return kb.ToString() + " KB"; 34 | } 35 | public static string WvBTGetMemoryInfoId(string assemblyFullName, string fieldName) 36 | => $"{assemblyFullName}$$${fieldName}"; 37 | public static string WvBTGetFirstRenderString(this bool? firstRender) 38 | { 39 | if (firstRender == null) return "n/a"; 40 | if (!firstRender.Value) return "no"; 41 | return "yes"; 42 | } 43 | public static string WvBTToDurationMSString(this long? duration) 44 | { 45 | if (duration == null) return "n/a"; 46 | return $"{duration.Value} ms"; 47 | } 48 | public static string WvBTToDurationMSString(this long duration) 49 | { 50 | return $"{duration} ms"; 51 | } 52 | public static string GetLimitValueAsString(this long limit, WvTraceSessionLimitType type) 53 | { 54 | switch (type) 55 | { 56 | case WvTraceSessionLimitType.MemoryTotal: 57 | case WvTraceSessionLimitType.MemoryDelta: 58 | return limit.WvBTToKilobytesString(); 59 | case WvTraceSessionLimitType.Duration: 60 | return limit.WvBTToDurationMSString(); 61 | default: 62 | return limit.ToString(); 63 | } 64 | } 65 | 66 | public static string WvBTToTimeString(this DateTimeOffset? timestamp) 67 | { 68 | if (timestamp == null) return "n/a"; 69 | return $"{timestamp.Value.ToString(WvConstants.TimestampFormat)} ms"; 70 | } 71 | public static string WvBTToTimeString(this DateTimeOffset timestamp) 72 | { 73 | return $"{timestamp.ToString(WvConstants.TimestampFormat)} ms"; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Utility/WvTraceUtility.Info.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.Serialization; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using WebVella.BlazorTrace.Models; 11 | 12 | namespace WebVella.BlazorTrace.Utility; 13 | public static partial class WvTraceUtility 14 | { 15 | public static WvTraceInfo? GetInfo(this object component, Guid? traceId, string? instanceTag, string methodName) 16 | { 17 | var componentType = component.GetType(); 18 | return new WvTraceInfo 19 | { 20 | TraceId = traceId, 21 | MethodName = methodName, 22 | ComponentFullName = componentType.FullName, 23 | ComponentName = (componentType.FullName ?? "").Split(".", StringSplitOptions.RemoveEmptyEntries).LastOrDefault(), 24 | InstanceTag = instanceTag, 25 | ModuleName = componentType?.Module.Name?.Replace(".dll", "") 26 | }; 27 | } 28 | 29 | public static WvTraceSessionMethodTrace? GetMatchingOnEnterTrace(this List traceList, Guid? traceId){ 30 | var orderedTraceList = traceList.OrderBy(x=> x.EnteredOn); 31 | if(traceId is not null) 32 | return traceList.FirstOrDefault(x =>x.EnteredOn is not null && x.ExitedOn is null && x.TraceId == traceId.Value); 33 | 34 | //any not exited will do 35 | return traceList.FirstOrDefault(x =>x.EnteredOn is not null && x.ExitedOn is null); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Utility/WvTraceUtility.Memory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.Serialization; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using WebVella.BlazorTrace.Models; 11 | 12 | namespace WebVella.BlazorTrace.Utility; 13 | public static partial class WvTraceUtility 14 | { 15 | public static long GetSize(this object obj, 16 | List memoryDetails, 17 | WvBlazorTraceConfiguration configuration, 18 | int maxDepth = 5) 19 | { 20 | if (obj == null) return 0; 21 | return MemorySizeCalculator.CalculateComponentMemorySize( 22 | component: obj, 23 | memoryDetails: memoryDetails, 24 | configuration: configuration, 25 | maxDepth: maxDepth 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/Utility/WvTraceUtility.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.Serialization; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using WebVella.BlazorTrace.Models; 11 | 12 | namespace WebVella.BlazorTrace.Utility; 13 | public static partial class WvTraceUtility 14 | { 15 | public static void ConsoleLog(string message) 16 | { 17 | #if DEBUG 18 | Console.WriteLine($"$$$$$$ [{DateTime.Now.ToString("HH:mm:ss:ffff")}] =>{message} "); 19 | #endif 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/WebVella.BlazorTrace.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0;net9.0 5 | enable 6 | enable 7 | WebVella.BlazorTrace 8 | 1.0.6 9 | WebVella 10 | WebVella 11 | Easy to plugin library for tracing most common problems when building a Blazor application like unnecessary renders, memory leaks, slow components 12 | WebVella 2025 13 | https://github.com/WebVella/WebVella.BlazorTrace 14 | README.md 15 | https://github.com/WebVella/WebVella.BlazorTrace 16 | git 17 | blazor,trace,component,memory,execution time, duration 18 | Initial release 19 | LICENSE 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Always 34 | 35 | 36 | 37 | 38 | 39 | Always 40 | 41 | 42 | 43 | 44 | 45 | 46 | True 47 | \ 48 | 49 | 50 | True 51 | \ 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/WvConstants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebVella.BlazorTrace; 8 | public static class WvConstants 9 | { 10 | public const string TimestampFormat = "HH:mm:ss ffff"; 11 | } 12 | -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/compilerconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "outputFile": "styles.css", 4 | "inputFile": "Styles/index.less" 5 | } 6 | ] -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/compilerconfig.json.defaults: -------------------------------------------------------------------------------- 1 | { 2 | "compilers": { 3 | "less": { 4 | "autoPrefix": "", 5 | "cssComb": "none", 6 | "ieCompat": true, 7 | "strictMath": false, 8 | "strictUnits": false, 9 | "relativeUrls": true, 10 | "rootPath": "", 11 | "sourceMapRoot": "", 12 | "sourceMapBasePath": "", 13 | "sourceMap": false 14 | }, 15 | "sass": { 16 | "autoPrefix": "", 17 | "includePath": "", 18 | "indentType": "space", 19 | "indentWidth": 2, 20 | "outputStyle": "nested", 21 | "Precision": 5, 22 | "relativeUrls": true, 23 | "sourceMapRoot": "", 24 | "lineFeed": "", 25 | "sourceMap": false 26 | }, 27 | "stylus": { 28 | "sourceMap": false 29 | }, 30 | "babel": { 31 | "sourceMap": false 32 | }, 33 | "coffeescript": { 34 | "bare": false, 35 | "runtimeMode": "node", 36 | "sourceMap": false 37 | }, 38 | "handlebars": { 39 | "root": "", 40 | "noBOM": false, 41 | "name": "", 42 | "namespace": "", 43 | "knownHelpersOnly": false, 44 | "forcePartial": false, 45 | "knownHelpers": [], 46 | "commonjs": "", 47 | "amd": false, 48 | "sourceMap": false 49 | } 50 | }, 51 | "minifiers": { 52 | "css": { 53 | "enabled": true, 54 | "termSemicolons": true, 55 | "gzip": false 56 | }, 57 | "javascript": { 58 | "enabled": true, 59 | "termSemicolons": true, 60 | "gzip": false 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/WebVella.BlazorTrace/scripts.js: -------------------------------------------------------------------------------- 1 | window.WebVellaBlazorTrace = { 2 | escapeKeyEventListeners: {}, 3 | escapeKeyEventListenerQueue: [], 4 | f1KeyEventListener: null, 5 | inited: false, 6 | initKeyListeners: function () { 7 | document.addEventListener("keydown", function (evtobj) { 8 | if (evtobj.code === "Escape") { 9 | if (!WebVellaBlazorTrace.escapeKeyEventListenerQueue || WebVellaBlazorTrace.escapeKeyEventListenerQueue.length == 0) return; 10 | evtobj.preventDefault(); 11 | evtobj.stopPropagation(); 12 | WebVellaBlazorTrace.executeEscapeKeyEventCallbacks(evtobj); 13 | } 14 | if (evtobj.code === "F1") { 15 | if (!WebVellaBlazorTrace.f1KeyEventListener) return; 16 | evtobj.preventDefault(); 17 | evtobj.stopPropagation(); 18 | WebVellaBlazorTrace.executeF1KeyEventCallbacks(evtobj); 19 | } 20 | }); 21 | WebVellaBlazorTrace.inited = true; 22 | }, 23 | addEscapeKeyEventListener: function (dotNetHelper, listenerId, methodName) { 24 | if (!WebVellaBlazorTrace.inited) { 25 | WebVellaBlazorTrace.initKeyListeners(); 26 | } 27 | WebVellaBlazorTrace.escapeKeyEventListeners[listenerId] = { dotNetHelper: dotNetHelper, methodName: methodName }; 28 | WebVellaBlazorTrace.escapeKeyEventListenerQueue.push(listenerId); 29 | return true; 30 | }, 31 | executeEscapeKeyEventCallbacks: function (eventData) { 32 | if (WebVellaBlazorTrace.escapeKeyEventListenerQueue && WebVellaBlazorTrace.escapeKeyEventListenerQueue.length > 0) { 33 | var lastRegisteredListenerId = WebVellaBlazorTrace.escapeKeyEventListenerQueue[WebVellaBlazorTrace.escapeKeyEventListenerQueue.length - 1]; 34 | const dotNetHelper = WebVellaBlazorTrace.escapeKeyEventListeners[lastRegisteredListenerId].dotNetHelper; 35 | const methodName = WebVellaBlazorTrace.escapeKeyEventListeners[lastRegisteredListenerId].methodName; 36 | if (dotNetHelper && methodName) { 37 | dotNetHelper.invokeMethodAsync(methodName, eventData.code); 38 | } 39 | } 40 | return true; 41 | }, 42 | removeEscapeKeyEventListener: function (listenerId) { 43 | if (WebVellaBlazorTrace.escapeKeyEventListeners && WebVellaBlazorTrace.escapeKeyEventListeners[listenerId]) { 44 | delete WebVellaBlazorTrace.escapeKeyEventListeners[listenerId]; 45 | WebVellaBlazorTrace.escapeKeyEventListenerQueue = WebVellaBlazorTrace.escapeKeyEventListenerQueue.filter(x => x != listenerId); 46 | } 47 | return true; 48 | }, 49 | 50 | addF1KeyEventListener: function (dotNetHelper, methodName) { 51 | if (!WebVellaBlazorTrace.inited) { 52 | WebVellaBlazorTrace.initKeyListeners(); 53 | } 54 | WebVellaBlazorTrace.f1KeyEventListener = { dotNetHelper: dotNetHelper, methodName: methodName }; 55 | return true; 56 | }, 57 | executeF1KeyEventCallbacks: function (eventData) { 58 | if (WebVellaBlazorTrace.f1KeyEventListener) { 59 | const dotNetHelper = WebVellaBlazorTrace.f1KeyEventListener.dotNetHelper; 60 | const methodName = WebVellaBlazorTrace.f1KeyEventListener.methodName; 61 | if (dotNetHelper && methodName) { 62 | dotNetHelper.invokeMethodAsync(methodName, eventData.code); 63 | } 64 | } 65 | return true; 66 | }, 67 | removeF1KeyEventListener: function () { 68 | if (WebVellaBlazorTrace.f1KeyEventListener) { 69 | WebVellaBlazorTrace.f1KeyEventListener = null; 70 | } 71 | return true; 72 | } 73 | } 74 | 75 | document.addEventListener("DOMContentLoaded", function () { 76 | WebVellaBlazorTrace.init(); 77 | }); -------------------------------------------------------------------------------- /tests/WebVella.BlazorTrace.Tests/Models/TestComponent.cs: -------------------------------------------------------------------------------- 1 | using Bunit; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.JSInterop; 5 | using Moq; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace WebVella.BlazorTrace.Tests; 13 | public class TestComponent : ComponentBase 14 | { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /tests/WebVella.BlazorTrace.Tests/WebVella.BlazorTrace.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0;net9.0 5 | enable 6 | enable 7 | false 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /tests/WebVella.BlazorTrace.Tests/WvBlazorTraceService/WvBlazorTraceServiceTests.Limits.cs: -------------------------------------------------------------------------------- 1 | using WebVella.BlazorTrace.Models; 2 | 3 | namespace WebVella.BlazorTrace.Tests; 4 | 5 | public partial class WvBlazorTraceServiceTests : BaseTest 6 | { 7 | 8 | [Fact] 9 | public void LimitDuration1() 10 | { 11 | lock (_locker) 12 | { 13 | //given 14 | var options = new WvTraceMethodOptions { 15 | DurationLimitMS = 1 16 | }; 17 | var firstRender = true; 18 | var moduleName = "WebVella.BlazorTrace.Tests"; 19 | var componentName = "TestComponent"; 20 | var componentFullName = moduleName + "." + componentName; 21 | var methodName = "SlowMethod"; 22 | var traceId = Guid.NewGuid(); 23 | var instanceTag = Guid.NewGuid().ToString(); 24 | var customData = Guid.NewGuid().ToString(); 25 | //when 26 | WvBlazorTraceServiceMock.Object.OnEnter( 27 | component: Component, 28 | traceId: traceId, 29 | options: options, 30 | firstRender: firstRender, 31 | instanceTag: instanceTag, 32 | customData: customData, 33 | methodName: methodName 34 | ); 35 | Thread.Sleep(5); 36 | WvBlazorTraceServiceMock.Object.OnExit( 37 | component: Component, 38 | traceId: traceId, 39 | options: options, 40 | firstRender: firstRender, 41 | instanceTag: instanceTag, 42 | customData: customData, 43 | methodName: methodName 44 | ); 45 | 46 | //than 47 | var queue = WvBlazorTraceServiceMock.Object.GetQueue(); 48 | Assert.NotEmpty(queue); 49 | WvBlazorTraceServiceMock.Object.ForceProcessQueue(); 50 | var (method,trace) = CheckTraceExists( 51 | moduleDict: WvBlazorTraceServiceMock.Object.GetModuleDict(), 52 | moduleName: moduleName, 53 | componentFullName: componentFullName, 54 | componentName: componentName, 55 | instanceTag: instanceTag, 56 | methodName: methodName, 57 | traceId: traceId 58 | ); 59 | Assert.Single(method.LimitHits); 60 | var limitHit = method.LimitHits.First(); 61 | Assert.Equal(WvTraceSessionLimitType.Duration,limitHit.Type); 62 | Assert.Equal(options.DurationLimitMS,limitHit.Limit); 63 | Assert.False(limitHit.IsOnEnter); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /tests/WebVella.BlazorTrace.Tests/WvBlazorTraceService/WvBlazorTraceServiceTests.MethodCalls.cs: -------------------------------------------------------------------------------- 1 | using WebVella.BlazorTrace.Models; 2 | 3 | namespace WebVella.BlazorTrace.Tests; 4 | 5 | public partial class WvBlazorTraceServiceTests : BaseTest 6 | { 7 | 8 | [Fact] 9 | public void OnEnterTestBaseCalls() 10 | { 11 | lock (_locker) 12 | { 13 | //given 14 | var options = new WvTraceMethodOptions { }; 15 | var firstRender = true; 16 | var moduleName = "WebVella.BlazorTrace.Tests"; 17 | var componentName = "TestComponent"; 18 | var componentFullName = moduleName + "." + componentName; 19 | var methodsList = new List{ 20 | "OnInitialized","OnInitializedAsync", 21 | "OnParametersSet","OnParametersSetAsync", 22 | "OnAfterRender","OnAfterRenderAsync", 23 | "ShouldRender", 24 | "Dispose","DisposeAsync", 25 | "OnEnterTestOther","OnEnterTestOtherAsync" 26 | }; 27 | 28 | foreach (var methodName in methodsList) 29 | { 30 | var traceId = Guid.NewGuid(); 31 | var instanceTag = Guid.NewGuid().ToString(); 32 | var customData = Guid.NewGuid().ToString(); 33 | //when 34 | Action action = () => WvBlazorTraceServiceMock.Object.OnEnter( 35 | component: Component, 36 | traceId: traceId, 37 | options: options, 38 | firstRender: firstRender, 39 | instanceTag: instanceTag, 40 | customData: customData, 41 | methodName: methodName 42 | ); 43 | var ex = Record.Exception(action); 44 | Assert.Null(ex); 45 | //than 46 | var queue = WvBlazorTraceServiceMock.Object.GetQueue(); 47 | Assert.NotEmpty(queue); 48 | WvBlazorTraceServiceMock.Object.ForceProcessQueue(); 49 | var (method, trace) = CheckTraceExists( 50 | moduleDict: WvBlazorTraceServiceMock.Object.GetModuleDict(), 51 | moduleName: moduleName, 52 | componentFullName: componentFullName, 53 | componentName: componentName, 54 | instanceTag: instanceTag, 55 | methodName: methodName, 56 | traceId: traceId 57 | ); 58 | Assert.NotNull(trace.EnteredOn); 59 | Assert.NotNull(trace.OnEnterOptions); 60 | Assert.Null(trace.ExitedOn); 61 | } 62 | } 63 | } 64 | 65 | [Fact] 66 | public void OnExitTestBaseCalls() 67 | { 68 | lock (_locker) 69 | { 70 | //given 71 | var options = new WvTraceMethodOptions { }; 72 | var firstRender = true; 73 | var moduleName = "WebVella.BlazorTrace.Tests"; 74 | var componentName = "TestComponent"; 75 | var componentFullName = moduleName + "." + componentName; 76 | var methodsList = new List{ 77 | "OnInitialized","OnInitializedAsync", 78 | "OnParametersSet","OnParametersSetAsync", 79 | "OnAfterRender","OnAfterRenderAsync", 80 | "ShouldRender", 81 | "Dispose","DisposeAsync", 82 | "OnEnterTestOther","OnEnterTestOtherAsync" 83 | }; 84 | foreach (var methodName in methodsList) 85 | { 86 | var traceId = Guid.NewGuid(); 87 | var instanceTag = Guid.NewGuid().ToString(); 88 | var customData = Guid.NewGuid().ToString(); 89 | //when 90 | Action action = () => WvBlazorTraceServiceMock.Object.OnExit( 91 | component: Component, 92 | traceId: traceId, 93 | options: options, 94 | firstRender: firstRender, 95 | instanceTag: instanceTag, 96 | customData: customData, 97 | methodName: methodName 98 | ); 99 | var ex = Record.Exception(action); 100 | Assert.Null(ex); 101 | //than 102 | var queue = WvBlazorTraceServiceMock.Object.GetQueue(); 103 | Assert.NotEmpty(queue); 104 | WvBlazorTraceServiceMock.Object.ForceProcessQueue(); 105 | var (method, trace) = CheckTraceExists( 106 | moduleDict: WvBlazorTraceServiceMock.Object.GetModuleDict(), 107 | moduleName: moduleName, 108 | componentFullName: componentFullName, 109 | componentName: componentName, 110 | instanceTag: instanceTag, 111 | methodName: methodName, 112 | traceId: traceId 113 | ); 114 | Assert.Null(trace.EnteredOn); 115 | Assert.NotNull(trace.ExitedOn); 116 | Assert.NotNull(trace.OnExitOptions); 117 | } 118 | } 119 | } 120 | 121 | [Fact] 122 | public void SignalTestBaseCalls() 123 | { 124 | lock (_locker) 125 | { 126 | //given 127 | var options = new WvTraceSignalOptions { }; 128 | var moduleName = "WebVella.BlazorTrace.Tests"; 129 | var signalName = "test-signal"; 130 | var componentName = "TestComponent"; 131 | var componentFullName = moduleName + "." + componentName; 132 | var methodName = "CustomMethod"; 133 | 134 | var traceId = Guid.NewGuid(); 135 | var instanceTag = Guid.NewGuid().ToString(); 136 | var customData = Guid.NewGuid().ToString(); 137 | //when 138 | Action action = () => WvBlazorTraceServiceMock.Object.OnSignal( 139 | caller: Component, 140 | signalName: signalName, 141 | instanceTag: instanceTag, 142 | customData: customData, 143 | options: options, 144 | methodName: methodName 145 | ); 146 | var ex = Record.Exception(action); 147 | Assert.Null(ex); 148 | //than 149 | var queue = WvBlazorTraceServiceMock.Object.GetQueue(); 150 | Assert.NotEmpty(queue); 151 | WvBlazorTraceServiceMock.Object.ForceProcessQueue(); 152 | var (method, trace) = CheckSignalTraceExists( 153 | signalDict: WvBlazorTraceServiceMock.Object.GetSignalDict(), 154 | moduleName: moduleName, 155 | signalName : signalName, 156 | componentFullName: componentFullName, 157 | instanceTag: instanceTag, 158 | methodName: methodName 159 | ); 160 | Assert.NotNull(trace.SendOn); 161 | Assert.NotNull(trace.Options); 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tests/WebVella.BlazorTrace.Tests/WvBlazorTraceService/WvBlazorTraceServiceTests.Modal.cs: -------------------------------------------------------------------------------- 1 | using WebVella.BlazorTrace.Models; 2 | using WebVella.BlazorTrace.Utility; 3 | namespace WebVella.BlazorTrace.Tests; 4 | 5 | public partial class WvBlazorTraceServiceTests : BaseTest 6 | { 7 | 8 | [Fact] 9 | public void TraceRowGenerationSameSnapshot() 10 | { 11 | lock (_locker) 12 | { 13 | //given 14 | var primarySN = GetSnapshot(); 15 | var mutedTraces = new List(); 16 | var pins = new List(); 17 | 18 | //when 19 | var result = new List(); 20 | Action action = () => result = primarySN.GenerateMethodTraceRows(primarySN, mutedTraces,pins); 21 | var ex = Record.Exception(action); 22 | Assert.Null(ex); 23 | Assert.Single(result); 24 | var trRow = CheckTraceRowExists( 25 | traceRows: result, 26 | moduleName: ModuleName, 27 | componentFullName: ComponentFullName, 28 | componentName: ComponentName, 29 | instanceTag: InstanceTag, 30 | methodName: MethodName 31 | ); 32 | Assert.Single(trRow.TraceList); 33 | Assert.NotNull(trRow.MethodComparison); 34 | Assert.Equal(0, trRow.MethodComparison.TraceListChange); 35 | Assert.Equal(0, trRow.MethodComparison.LastDurationChangeMS); 36 | 37 | Assert.NotNull(trRow.MemoryComparison); 38 | Assert.Equal(0, trRow.MemoryComparison.LastMemoryChangeBytes); 39 | } 40 | } 41 | 42 | [Fact] 43 | public void TraceRowGenerationSnapshotComparison() 44 | { 45 | lock (_locker) 46 | { 47 | //given 48 | var primarySN = GetSnapshot(); 49 | var secondarySN = GetSnapshot(); 50 | secondarySN.Id = Guid.NewGuid(); 51 | secondarySN.Name = "secondary"; 52 | var secondaryMethod = secondarySN.ModuleDict[ModuleName] 53 | .ComponentDict[ComponentFullName] 54 | .TaggedInstances[0] 55 | .OnInitialized; 56 | secondaryMethod.TraceList.Add(new WvTraceSessionMethodTrace 57 | { 58 | TraceId = Guid.NewGuid(), 59 | OnEnterCustomData = OnEnterCustomData, 60 | OnExitCustomData = OnEnterCustomData, 61 | EnteredOn = TimeStamp.AddSeconds(30), 62 | ExitedOn = TimeStamp2.AddSeconds(30).AddMilliseconds(DelayMS), 63 | OnEnterFirstRender = FirstRender, 64 | OnExitFirstRender = FirstRender, 65 | OnEnterMemoryBytes = MemoryBytes, 66 | OnEnterMemoryInfo = new List{ 67 | new WvTraceMemoryInfo{ 68 | AssemblyName = ModuleName, 69 | FieldName = FieldName, 70 | Size = MemoryBytes 71 | } 72 | }, 73 | OnExitMemoryBytes = MemoryBytes + ExtraMemoryBytes, 74 | OnExitMemoryInfo = new List{ 75 | new WvTraceMemoryInfo{ 76 | AssemblyName = ModuleName, 77 | FieldName = FieldName, 78 | Size = MemoryBytes + ExtraMemoryBytes 79 | } 80 | }, 81 | OnEnterOptions = MethodOptions, 82 | OnExitOptions = MethodOptions 83 | }); 84 | var mutedTraces = new List(); 85 | var pins = new List(); 86 | //when 87 | var result = new List(); 88 | Action action = () => result = primarySN.GenerateMethodTraceRows(secondarySN, mutedTraces, pins); 89 | var ex = Record.Exception(action); 90 | Assert.Null(ex); 91 | Assert.Single(result); 92 | var trRow = CheckTraceRowExists( 93 | traceRows: result, 94 | moduleName: ModuleName, 95 | componentFullName: ComponentFullName, 96 | componentName: ComponentName, 97 | instanceTag: InstanceTag, 98 | methodName: MethodName 99 | ); 100 | Assert.Equal(2, trRow.TraceList.Count); 101 | Assert.Equal(MemoryBytes + ExtraMemoryBytes, trRow.LastMemoryBytes); 102 | Assert.Equal(DelayMS * 2, trRow.LastDurationMS); 103 | Assert.NotNull(trRow.MethodComparison); 104 | Assert.Equal(1, trRow.MethodComparison.TraceListChange); 105 | Assert.Equal(DelayMS, trRow.MethodComparison.LastDurationChangeMS); 106 | 107 | Assert.NotNull(trRow.MemoryComparison); 108 | Assert.Equal(ExtraMemoryBytes, trRow.MemoryComparison.LastMemoryChangeBytes); 109 | } 110 | } 111 | } 112 | --------------------------------------------------------------------------------