Зачастую необходимо собирать статистику по производительности методов приложения в режиме реального времени (когда приложение уже запущено), чтобы выявлять его узкие места, и видеть, какая часть приложения тормозит. При этом было бы неплохо помимо самих данных по производительности (время отработки метода, дата начала и окончания его вызова) хранить контекст вызова, при котором отслеживается производительность (такие как аргументы вызова метода и произвольные добавляемые разработчиком данные). Ну и "вишенкой на торте" можно считать удобство и простоту используемого инструмента, что тоже немаловажно. Для решения этих задач и была разработана кросс-платформенная open-source .NET библиотека Unchase.FluentPerformanceMeter. Итак, данная статья представляет собой описание работы с Unchase Fluent Performance Meter — кросс-платформенной open-source .Net Standard 2.0 библиотекой, предназначенной для подсчёта производительности выполнения методов. Библиотека может быть использована в .NET Core и .NET Framework приложениях, поддерживающих .Net Standard 2.0, и позволяет: Полученные в результате замеров производительности методов данные можно использовать для анализа производительности приложения (отдельных его частей, как внутренних — собственный код, так и внешних — код используемых библиотек) и вывести в удобном для вас графическом виде. Для использования библиотеки установите NuGet пакет в ваш проект: Далее приведён простейший пример использования библиотеки (без конфигурирования и дополнительных настроек) для замера производительности метода (Action) SimpleWatchingMethodStart контроллера (Controller) PerformanceMeterController Asp.Net Core 2.2 WebAPI приложения. Для это можно использовать метод расширения .WatchingMethod().Start() или аналогичный по функциональности .StartWatching().
С версии v1.0.5 также можно использовать .WatchingMethod().Start(SimpleWatchingMethodStart) или .StartWatching(SimpleWatchingMethodStart) с указанием имени метода.  Для получения результатов замеров производительности публичных методов класса-контроллера PerformanceMeterController можно вызвать следующий метод: После вызова метода SimpleWatchingMethodStart при вызове GetPerformanceInfo получим: Начиная с версии v2.1.0 появилась возможность получать результаты замеров производительности методов класса, используя встроенный DI в ASP.NET Core приложении.
Для этого необходимо добавить в Startap.cs следующий код: После чего, используя DI, можно получить результаты, например, следующим образом: Начиная с версии v1.1.0 появилась возможность мерять производительность методов в AspNetCore MVC приложении с помощью DiagnosticSource и специального атрибута WatchingWithDiagnosticSourceAttribute.
Для этого необходимо добавить в проект NuGet пакет Unchase.FluentPerformanceMeter.AspNetCore.Mvc, и добавить в Startap.cs следующий код: После чего пометить атрибутом WatchingWithDiagnosticSourceAttribute либо отдельные методы: либо весь класс: Начиная с версии v1.2.0 появилась возможность добавлять аргументы вызова к пользовательским данным замера производительности методов в AspNetCore MVC приложении с помощью специального атрибута AddMethodArgumentsToCustomDataAttribute в связке с атрибутом WatchingWithDiagnosticSourceAttribute: После вызова метода SimpleWatchingMethodStartWithArgs при вызове GetPerformanceInfo получим: Начиная с версии v2.0.0 появилась возможность мерять производительность методов в AspNetCore MVC приложении с помощью специального атрибута WatchingPerformanceAttribute, а также конфигурировать сбор производительности методов контроллера в Startup.cs.
Для этого необходимо добавить в проект NuGet пакет Unchase.FluentPerformanceMeter.AspNetCore.Mvc, и добавить в Startap.cs следующий код: После чего пометить атрибутом WatchingPerformanceAttribute либо отдельные методы: либо весь класс: Чтобы замерить производительность public метода public класса сторонней используемой библиотеки, необходимо явно задать сам класс и имя его метода: Выполненный метод вернёт: Вы можете получить данные о вызове этого метода через вызов: В ответе на вызов этого метода будет: Можно добавить дополнительные данные (Custom Data) для всех замеров производительности методов конкретного класса. Например, в статическом конструкторе класса-контроллера PerformanceMeterController: Кроме того, можно добавить дополнительные данные (Custom Data) для определённого замера с помощью метода расширения .WithSettingData.CustomData("<key>", <value>) (в том числе, через специальный атрибут метода MethodCustomDataAttribute) и для каждого шага (Step) этого замера, добавленного с помощью метода расширения .Step("<step_name>"), — с помощью метода расширения .AddCustomData("<key>", <value>): В результате при вызове GetPerformanceInfo получим: Вы можете не учитывать в замере производительности отдельные части метода (с помощью .Ignore() или .Executing().WithoutWatching().Start(<Action>)), а также не сохранять отдельные шаги (метод расширения .StepIf("<step_name>", <minSaveMs>)), если они не удовлетворяют условию (при этом время выполнения шага будет учитываться во времени выполнения метода): В результате получим: Для добавления команды, которая будет гарантированно исполнена по завершении замера производительности метода, необходимо создать класс команды, который будет реализовывать интерфейс IPerformanceCommand.
При этом вы можете через конструктор созданной команды передавать произвольные данные, которые будут использованы при её выполнении. Например: Добавить команду (IPerformanceCommand) и действие (Action), чтобы они выполнились по окончании замера, можно следующим способом: В результате, по окончанию замера производительности метода в Debug-консоли будет выведено: Если вам необходимо обрабатывать исключения, которые могут возникнуть при выполнении части метода, для которого отслеживается производительность, то необходимо добавить обработчик исключений (Exception handler) следующим образом: Где класс CustomException, например: В результате в Debug-консоли будет выведено: Кроме того, вы можете задать обработчик исключений, который будет использован по-умолчанию для замеров производительности любого метода данного класса, например, через статический конструктор класса-контроллера PerformanceMeterController: Вы можете установить время хранения данных замеров производительности методов, по истечении которого эти данные будут удалены. Для каждого класса, для которого производится замер, это время устанавливается отдельно. Например, время можно задать через статический конструктор класса-контроллера PerformanceMeterController: Вы можете задать данные о том, кто вызывает метод, с помощью метода расширения .CallerFrom("<caller_name>") (ему передаётся либо строка, либо IHttpContextAccessor) или специального атрибута метода . При этом, если используется и атрибут и метод расширения, то значение будет браться из последнего. Для добавления места вызова замера производительности используется метод расширения .WithSettingData.CallerSourceData(). Для остановки замера производительности внутри блока using используется метод расширения .StopWatching() или непосредственно метод Dispose(): В результате вызова метода GetPerformanceInfo получите: Таким образом, представленное решение позволяет отчасти автоматизировать сбор информации о производительности методов .NET приложений достаточно удобным способом. Собранные данные можно визуализировать тем способом, который больше подходит каждому конкретному разработчику. Конечно, библиотека не решаает все задачи, связанные со сбором данных по производительности методов, но стремится упростить наиболее часто встречающиеся из них. Библиотека является open-source решением, любые пожелания и предложения по её развитию только приветствуются, как и bug-report'ы (все желающие могут перейти по ссылке; автор будет признателен за любую помощь!). 08.03.2020 — добавлено описание новых возможностей для версии v2.0.0 в разделе Измерение производительности метода с помощью атрибута WatchingPerformanceAttribute. 14.03.2020 — добавлено описание новых возможностей для версии v2.1.0 в разделе Использование DI для получения результатов замера производительности. Программист