Open sandboxFocusImprove this doc

Logging example, step 6: Adding the aspect programmatically

In the previous examples, we applied the logging aspect manually using the [Log] custom attribute. But when we must add logging to all methods of a namespace, doing it manually becomes tedious.

We can programmatically filter the code model of our project and add aspects to desired methods by adding a ProjectFabric to our code. Fabrics are compile-time classes executed by Metalama during compilation or from our IDE. They can add aspects to any eligible target declaration. For details, see Adding many aspects simultaneously.

The following code adds the logging aspect to all public methods of public types:

1using Metalama.Framework.Fabrics;
2using Metalama.Framework.Code;
3
4internal class Fabric : ProjectFabric
5{
6    public override void AmendProject(IProjectAmender amender) =>
7        amender
8            .SelectTypes()
9            .Where(type => type.Accessibility == Accessibility.Public)
10            .SelectMany(type => type.Methods)
11            .Where(method =>
12                method.Accessibility == Accessibility.Public && method.Name != "ToString")
13            .AddAspectIfEligible<LogAttribute>();
14}
Warning

It is important to exclude the ToString method from logging; otherwise, infinite recursion could occur.

We can see that the Calculator class has been transformed, even though there is no longer any custom attribute:

Source Code



1public class Calculator
2{


















3    public double Add(double a, double b) => a + b;









4}
Transformed Code
1using System;
2using Microsoft.Extensions.Logging;
3
4public class Calculator
5{
6    public double Add(double a, double b) { var isTracingEnabled = _logger.IsEnabled(LogLevel.Trace);
7        if (isTracingEnabled)
8        {
9            _logger.LogTrace($"Calculator.Add(a = {{{a}}}, b = {{{b}}}) started.");
10        }
11
12        try
13        {
14            double result;
15            result = a + b;if (isTracingEnabled)
16            {
17                _logger.LogTrace($"Calculator.Add(a = {{{a}}}, b = {{{b}}}) returned {result}.");
18            }
19
20            return (double)result;
21        }
22        catch (Exception e) when (_logger.IsEnabled(LogLevel.Warning))
23        {
24            _logger.LogWarning($"Calculator.Add(a = {{{a}}}, b = {{{b}}}) failed: {e.Message}");
25            throw;
26        }
27    }
28private ILogger _logger;
29
30    public Calculator(ILogger<Calculator> logger = default(global::Microsoft.Extensions.Logging.ILogger<global::Calculator>))
31    {
32        this._logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
33    }
34}
Warning

Including sensitive information (such as user credentials or personal data) in logs can pose a security risk. You should be cautious when adding parameter values to logs and avoid exposing sensitive data. To remove sensitive information from the logs, see Logging example, step 7: Removing sensitive data.