Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# Entity Framework Profiler for ASP.Net Core


A tiny profiler without hassle.
![screenshot](./docs/img/chrome_qKlLJE0ANE.png)


```
┌────────────────────────────────────────────────────────────────────────────────┐
│ │
Expand Down Expand Up @@ -35,10 +31,15 @@ A tiny profiler without hassle.
└────────────────────────────────────────────────────────────────────────────────┘
```


A tiny profiler without hassle.
![screenshot](./docs/img/chrome_qKlLJE0ANE.png)


## Installation

```
dotnet add package NanoDbProfiler.AspNetCore --version 0.1.23-alpha-g1a0a4554d2 --source https://www.myget.org/F/guneysu/api/v3/index.json
dotnet add package NanoDbProfiler.AspNetCore --version 8.0.10 --source https://www.myget.org/F/guneysu/api/v3/index.json
```

```csharp
Expand Down
5 changes: 2 additions & 3 deletions pakefile.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
$msbuild = "C:\Program Files\Microsoft Visual Studio\2022\Community\\MSBuild\Current\Bin\amd64\MSBuild.exe"
$msbuild = "C:\Program Files\Microsoft Visual Studio\2022\Preview\\MSBuild\Current\Bin\amd64\MSBuild.exe"
$msbuild = "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe"
$msbuild = "C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64\MSBuild.exe"

function Init {
# dotnet tool install -g nbgv
Expand Down Expand Up @@ -42,7 +42,6 @@ function Patch-Version {

function Build {


. "${msbuild}" /bl `
.\src\NanoDbProfiler.AspNetCore\NanoDbProfiler.AspNetCore.csproj `
-p:Configuration=Release `
Expand Down
1 change: 1 addition & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Deterministic>true</Deterministic>
<EfCoreRelationPackage>8.0.11</EfCoreRelationPackage>
<GitVersionBaseDirectory>$(MSBuildThisFileDirectory)</GitVersionBaseDirectory>
</PropertyGroup>
<ItemGroup>
Expand Down
26 changes: 20 additions & 6 deletions src/Example/Example.csproj
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DefineConstants>$(DefineConstants);EFCORE_PROFILER_TOOLBAR</DefineConstants>
</PropertyGroup>

<ItemGroup>
<None Remove="db.sqlite" />
<None Remove="db.sqlite-shm" />
<None Remove="db.sqlite-wal" />
<None Remove="db.sqlite" />
<None Remove="db.sqlite-shm" />
<None Remove="db.sqlite-wal" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="$(EfCoreRelationPackage)" />
<PackageReference Include="System.Text.Json" Version="8.0.*" />
</ItemGroup>


<ItemGroup Condition="$(DefineConstants.Contains('NANODBPROFILER'))">
<ProjectReference Include="..\NanoDbProfiler.AspNetCore\NanoDbProfiler.AspNetCore.csproj" />
</ItemGroup>

<ItemGroup Condition="$(DefineConstants.Contains('EFCORE_PROFILER_TOOLBAR')) and $(Configuration) == 'Debug'">
<ProjectReference Include="..\..\..\github.com\guneysus\EfCoreQueryToolbar.git\src\EfCoreQueryToolbar\EfCoreQueryToolbar.csproj" />
</ItemGroup>

<ItemGroup Condition="$(Configuration) == 'Release'">
<PackageReference Version="0.0.1-alpha-gde64f9e45e" Include="EfCoreQueryToolbar" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NanoDbProfiler.AspNetCore\NanoDbProfiler.AspNetCore.csproj" />
<ProjectReference Include="X:\git\github.com\guneysus\sql-query-profiler\src\DbQueryTracer.EfCore\DbQueryTracer.EfCore.csproj" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions src/Example/Example.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example.csproj", "{FB0C2DC9-B030-4E94-933E-4D57671CEE08}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FB0C2DC9-B030-4E94-933E-4D57671CEE08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB0C2DC9-B030-4E94-933E-4D57671CEE08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB0C2DC9-B030-4E94-933E-4D57671CEE08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB0C2DC9-B030-4E94-933E-4D57671CEE08}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2FD7FBBB-C0F2-4F98-BAD9-BCD8B35FA502}
EndGlobalSection
EndGlobal
9 changes: 0 additions & 9 deletions src/Example/NanoDbProfilerEfCoreQueryInterceptor.cs

This file was deleted.

235 changes: 235 additions & 0 deletions src/Example/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
@page
@model Example.Pages.IndexModel
@{
}


<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>NanoDbProfiler for Entity Framework Core</title>
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<style>

/* General scrollbar styling for the page */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}

::-webkit-scrollbar-track {
background: #333;
}

::-webkit-scrollbar-thumb {
background-color: #555;
border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
background-color: #777;
}

/* Toolbar scrollbar styling */
#query-log::-webkit-scrollbar {
width: 8px;
}

#query-log::-webkit-scrollbar-track {
background: #222;
}

#query-log::-webkit-scrollbar-thumb {
background-color: #555;
border-radius: 4px;
}

#query-log::-webkit-scrollbar-thumb:hover {
background-color: #777;
}

/* Style for visually separating records */
.query-record {
border: 1px solid #555;
padding: 0 8px 8px 8px;
border-radius: 8px;
margin-bottom: 8px;
/* background-color: #2c2c2c; */
position: relative;
}

/* Duration bar styling */
.duration-bar {
height: 10px;
background-color: #4CAF50;
/* Default color for short queries */
border-radius: 5px;
margin-top: 5px;
}

</style>
</head>
<body>

<div id="app">
<div id="dev-toolbar">
<h2>NanoDB Profiler & Sample Queries</h2>
<button onclick="loadQueries()">Refresh</button>
<button onclick="purgeQueries()">Clean</button>
<button onclick="loadQuery(urlSelect.value)">Repeat</button>

<label for="urlSelect">Choose an endpoint:</label>
<select id="urlSelect" onchange="loadQuery(this.value)">
<!-- URLs will be populated by JavaScript -->
</select>

<div id="responseContainer" style="display: none;">
<h3>Response:</h3>
<b id="responseStatus"></b>
<div id="responseData"></div>
</div>
</div>

<div id="queryList" class="query-list">
<!-- Query records will be populated here -->
</div>
</div>

<script>
const urls = [
'/insert',
'/update',
'/select/single/1',
'/select/single/2',
'/select/all',
'/select/scalar',
'/select/max-id',
'/select/count',
'/select/sum',
'/select/orderby-desc',
'/select/avg',
'/select/starts-with',
'/select/ends-with',
'/select/contains',
'/select/distinct-by',
'/select/find',
'/delete/single',
'/delete/all'

];

// Populate select options
const urlSelect = document.getElementById('urlSelect');
urls.forEach(url => {
const option = document.createElement('option');
option.value = url;
option.textContent = url;
urlSelect.appendChild(option);
});

let summaries = [];

function getMaxDuration() {
if (summaries.length === 0) return 0;
return Math.max(...summaries.map(s => s.p95));
}

function getDurationBarColor(p95) {
const maxDuration = getMaxDuration();
if (p95 > maxDuration * 0.75) {
return '#ff5555';
} else if (p95 > maxDuration * 0.5) {
return '#ffbf00';
}
return '';
}

async function loadQuery(endpoint, method = 'get') {
try {
let response;
switch (method.toLowerCase()) {
case 'post':
response = await axios.post(endpoint);
break;
case 'put':
response = await axios.put(endpoint);
break;
case 'delete':
response = await axios.delete(endpoint);
break;
case 'get':
default:
response = await axios.get(endpoint);
break;
}

const responseContainer = document.getElementById('responseContainer');
const responseStatus = document.getElementById('responseStatus');
const responseData = document.getElementById('responseData');

responseContainer.style.display = 'block';
responseStatus.textContent = `${response.status} ${response.statusText}`;
responseData.innerHTML = response.data;
loadQueries();
} catch (error) {
console.error(`${method.toUpperCase()} Error:`, error);
responseStatus.textContent = `${error.response.status} ${error.response.statusText}`;
responseData.innerHTML = error.response.data;
}
}

async function loadQueries() {
try {
const response = await axios.request({
method: 'get',
url: "/query-log",
headers: {
'accept': 'application/json'
},
});

summaries = response.data.summaries;
renderQueries();
} catch (error) {
console.error('Failed to load queries:', error);
}
}

function renderQueries() {
const queryList = document.getElementById('queryList');
queryList.innerHTML = '';
const maxDuration = getMaxDuration();

summaries.forEach(summary => {
const queryRecord = document.createElement('div');
queryRecord.className = 'query-record';
queryRecord.innerHTML = `
<pre>${summary.query}</pre>
<div class="duration-bar" style="
background-color: ${getDurationBarColor(summary.p95)};
width: ${(summary.p95 / maxDuration * 100)}%">
</div>
<div class="query-details">
<span>Total Count: ${summary.total}</span>
<span>Duration: ${summary.p95.toFixed(3)}ms</span>
</div>
`;
queryList.appendChild(queryRecord);
});
}

async function purgeQueries() {
await loadQuery('/query-log', 'delete');
}

// Initial load
loadQueries();
</script>
</body>

</html>
12 changes: 12 additions & 0 deletions src/Example/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Example.Pages
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
Loading