Jak do projektu jednoduše zavést logování vám ukážu na jednoduché ukázkové aplikaci. Zdrojové soubory si můžete stáhnout zde.
PostSharp nám nabízí velmi jednoduchý způsob jak zavézt logování, téměř bez práce. Klikneme na název metody a rozbalíme možnosti, které nám Visual Studio nabízí. Standartní klávesová zkratka je ctrl+.. Ze seznamu vybereme Add logging.
Zobrazí se nám dialog pro nastavení logování. Když klikneme na edit u profilu máme možnost nastavit, co a s jakou prioritou se bude zapisovat do logu.
V dalšímu kroku, máme na výběr back end, který chceme k logování použít. Já jsem zvolil knihovnu Log4Net.
V další obrazovce je shrnutí co vše PostSharp přidá do projektu.
Následuje instalace a dokončení.
K metodě AddEmailAddress se přidal atribut Log a do projektu se přidal soubor PostSharp2.pssln, který obsahuje nastavení logování.
[Log]
public void AddEmailAddress(string email)
{
if (email.IsEmail())
{
emailList.Add(email);
}
else
{
throw new EmailAddressInInvalidFormat(email);
}
}
Ještě potřebujeme nastavit Log4Net. Do App.config přidáme dvě sekce. Sekce configSection musí být uvedena jako první sekce hned za tagem <configuration>. Druhou sekcí je nastavení Log4Net. Výsledný App.config vypadá takhle:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Culture=neutral" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender,log4net">
<file value="Log.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
</configuration>
Ještě musíme do AssemblyInfo.cs přidat dva řádky aby se Log4Net nastavil.
using log4net.Config;
[assembly: XmlConfigurator(Watch = true)]
Aplikaci můžeme spustit
vytvoří se nám soubor Log.txt a bude obsahovat jeden řádek.
2014-12-07 22:15:14,549 [1] ERROR PostSharp2.Model.User - EmailAddressInInvalidFormatException: User.AddEmailAddress(this = {John Doe [email protected]}, string email = "john.doe.gmail.com")
Hromadné použití aspektů
Logování už je funkční, jen by se nám asi moc nelíbilo ke každé funkci dávat atribut [Log]. Proto existuje několik způsobů jak použít atribut plošně. Můžeme uvést atribut nad třídou a tím se aplikuje na všechny její metody.
[Log]
public class JsonUserService : IUserService
To pro naše použití, ale není stále dostatečné. Máme možnost nasadit aspekt na celý jmenný prostor. Do AssemblyInfo.cs přidáme následující dva řádky a smažeme atribut log z metody AddEmailAddress, protože již nebude potřeba.
using PostSharp.Patterns.Diagnostics;
[assembly: Log(AttributeTargetTypes = "PostSharp2.*", AttributePriority = 1)]
Tím použijeme aspekt Log na všech metodách ve jmenném prostoru PostSharp2 a ve všech vnořených jmenných prostorech.
Možnosti filtrování
Ne vždy chceme nastavit atribut úplně na všem. A proto jsou zde široké možnosti filtrování. Parametr AttributeExclude říká, že pro metody vyhovující filtru se aspekt Log nenastaví. AttributePriority určuje pořadí, ve kterém jsou aspekty aplikovány. Dále můžeme použít prefix regex díky tomu můžeme použít pro filtrování regulární výraz.
[assembly: Log(
AttributePriority = 2,
AttributeExclude = true,
AttributeTargetTypes = @"regex:PostSharp2.Extensions.*")]
Také je možné použít filtrování podle modifikátorů tříd. Takhle by vypadalo pravidlo přidávající aspekt všem statickým třídám z jmenného prostoru PostSharp2.
[assembly: Log(AttributeTargetTypes = "PostSharp2.*",
AttributeTargetTypeAttributes = MulticastAttributes.Static)]
Obdobným způsobem je možné filtrovat podle signatury metody. Například všechny metody s ref parametrem z jmenného prostoru PostSharp2.
[assembly: Log(AttributeTargetTypes = "PostSharp2.*",
AttributeTargetMemberAttributes = MulticastAttributes.RefParameter)]
V případě že by vám nestačily tyhle možnosti filtrování je možnost u Aspektu přepsat metodu CompileTimeValidate.
public override bool CompileTimeValidate(MethodBase method)
{
Type targetType = method.DeclaringType;
if (typeof(IDemandAdminRightToAccess).IsAssignableFrom(targetType))
{
Message.Write(targetType, SeverityType.None, "NotSupportedType", "The target type does not implement IUserService.");
return true;
}
return false;
}
Takhle se dá aplikovat aspekt na všechny třídy, které implementují dané rozhraní. Velmi užitečné je to například v případě práv, kdy stačí přidat třídě interface a o zbytek se postaráme v aspektu.