Send email alerts from Nlog for specific exceptions - email

I am working on configuring NLog configuration which works perfectly for logging into text files. Now on the top of this I want to set a conditional target as Mail which should get fired only for a specific set of exceptions. For example - if there is a PaymentFailedException, CardExpiredException then the NLog should target Mail.
I have checked the NLog documentation but I could not find any way to set it for specific set of exceptions. However, NLog allows for setting target as Mail for exception levels.

You could configure use the <when> for this.
e.g.
<logger name="*" writeTo="myMailTarget">
<filters>
<when condition="not contains('${exception:format=type}', 'PaymentFailedException") action="Ignore" />
</filters>
</logger>
See filtering log messages and <when> docs

Related

Add a hook to Sentry Logback to scrub data

I'm using the Logback SDK for Java to send events to Sentry as described in the documentation.
Snippet:
<conversionRule conversionWord="CUSTOM_CONVERSION_RULE"
converterClass="clazz..." />
...
<property scope="context" name="myEnc" value="%d{ISO8601,UTC} | %-5level | %-50thread | %-55logger{55} | %CUSTOM_CONVERSION_RULE" />
...
<appender name="SENTRY" class="io.sentry.logback.SentryAppender">
<dsn>...</dsn>
<encoder>${myEnc}</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
....
The initial problem was that the events sent to Sentry were not converted by my custom conversion rule. All the other appenders such as Console that use the property myEnc containing the conversion rule parse the data as expected. But it seems that the io.sentry.logback.SentryAppender in combination with the encoder somehow doesn't do that. The filter property is working as well as the dsn one, so I get the errors in Sentry but not with my custom parsing.
The version that I use for io.sentry.sentry-logback (and transitively sentry) is 1.7.24.
I then read about before-send hook from Sentry docs which is what I want to control what data is sent to Sentry and I had to upgrade to latest for that which is 3.1.3 at the time of writing this.
The Logback XML config changed a bit:
<appender name="SENTRY" class="io.sentry.logback.SentryAppender">
<options>
<dsn>...</dsn>
<beforeSend>????</beforeSend>
</options>
...
</appender>
From what I can see the before-send hook is exactly what I need to scrub the data when required because I don't want some info to be sent to Sentry. docs
Now, the second issue is that I don't know how to ref here a method. In the Java config there is a BiFunction that takes the event and can alter it. But I want to apply this hook to all my log events, that's why the only place it is configured is in the Logback SDK.
In Spring Boot for example there is a starter for Sentry and, off course, a bean that you can inject in the auto-configuration.
But, I'm using Scala with no Spring Boot.
Also, the project is already in prod so I cannot change lots of things and I'm looking for the smallest one that will allow me to add a hook to Logback's SDK for Sentry.
Here is the appender and it looks like (I'm not sure how it works) the options can be populated from XML and than pass to init that will take all them into account, including my before send hook.
I don't know if it's accepted to have two questions and only one referenced in the title but I didn't find a nicer way to ask/explain the problem, because one thing lead to another.
To summarize the questions:
Why that custom rule is not working with Logback Sentry's appender.
How can I let the appender know about my hook and use it.
Thanks in advance!
You can configure Sentry independently from appender configuration in logback.xml. For example:
public class Main {
private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
static {
Sentry.init(options -> {
options.setDsn("PUT YOUR DSN HERE");
options.setBeforeSend((sentryEvent, o) -> {
sentryEvent.setTag("custom", "tag");
return sentryEvent;
});
});
}
public static void main(String[] args) {
LOGGER.error("oops");
}
}
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="sentry" class="io.sentry.logback.SentryAppender" />
<root level="debug">
<appender-ref ref="console"/>
<appender-ref ref="sentry"/>
</root>
</configuration>
Check complete code sample in github repo: https://github.com/maciej-scratches/sentry-logback-custom-config

I have a failing case when making an IDP connection using pingfederate

The server.log says "signature_status": "UNVERIFIED". Is this a certificate issue?
Also what are the best ways to read the pingfederate logs in windows machine.
That sounds like an issue with signature verification, which could be the cert itself but is more likely a configuration issue. More information is really needed to know which it is.
I assume the issue you are having with reading logs on windows machines is because the files are large or are moving quickly. If the files are too big you can modify the log4j2.xml config file at appdir/pingfed*/pingfed*/server/default/conf/log4j2.xml to reduce the log size to something easier to read in notepad. Here is an example rolling file appender that should leave you with easily maneageable files.
<RollingFile name="FILE" fileName="${sys:pf.log.dir}/server.log"
filePattern="${sys:pf.log.dir}/server.log.%i" ignoreExceptions="false">
<PatternLayout>
<!-- Uncomment this if you want to use UTF-8 encoding instead
of system's default encoding.
<charset>UTF-8</charset> -->
<pattern>%d %X{trackingid} %-5p [%c] %m%n</pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy
size="20000 KB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
If you issue is that the files are moving too fast to read then you might consider using something like baretail or Get-Content in powershell now that it has a tail switch.

Sitecore 8.1 error: "No session Id managers were found to manage the session Id for the current request"

I'm attempting to get a basic layout up and running in Sitecore 8.1, and I've hit an error about which I can find very little information. When attempting to view any page (even the backend interface or connecting from Sitecore Rocks), I get the message "No session Id managers were found to manage the session Id for the current request."
Some Googling suggests that this has to do with some issues with the out-of-box session provider and recommends swapping it out for keeping the sessions in Mongo. Sitecore's documentation provides a description of this, both for shared and private sessions. I've attempted to implement those but continue to receive the same error.
Here's my code as it stands now:
App_Config/Include/MongoSessionProvider.config
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<tracking>
<sharedSessionState>
<providers>
<clear/>
<add name="mongo" type="Sitecore.SessionProvider.MongoDB.MongoSessionProvider, Sitecore.SessionProvider.MongoDB" connectionString="session" pollingInterval="2" compression="true" sessionType="shared"/>
</providers>
</sharedSessionState>
</tracking>
</sitecore>
</configuration>
App_Config/Include/ConnectionStrings.config (excerpt)
<add name="session" connectionString="mongodb://localhost/sharedsession" />
Web.config (excerpt)
<sessionState mode="Custom" cookieless="false" timeout="20" sessionIDManagerType="Sitecore.FXM.SessionManagement.ConditionalSessionIdManager" customProvider="mongo">
<providers>
<add name="mongo" type="Sitecore.SessionProvider.MongoDB.MongoSessionStateProvider, Sitecore.SessionProvider.MongoDB" sessionType="Standard" connectionStringName="session" pollingInterval="2" compression="true" />
<add name="mssql" type="Sitecore.SessionProvider.Sql.SqlSessionStateProvider, Sitecore.SessionProvider.Sql" sessionType="Standard" connectionStringName="session" pollingInterval="2" compression="true" />
</providers>
</sessionState>
Note that this is on my local development machine. I have Mongo running (and confirmed its connection to Sitecore), and I created both the session and sharedsession databases in it using use session and use sharedsession, which I understand to be the way to create DBs in Mongo.
Am I missing something here? Or does the error simply not mean what I think it means?
The message you are seeing is not supposed to be an error, it is rather a log warning. It is related to retrieving the configuration of the Session ID Manager rather that to the configuration of the session itself.
Why this warning normally appears
In the Sitecore.config under <pipelines> there's the getSessionIdManager pipeline defined.
<getSessionIdManager>
</getSessionIdManager>
In the Sitecore.FXM.config, there is a processor configured for this pipeline:
<getSessionIdManager>
<processor type="Sitecore.FXM.Pipelines.ChooseSessionIdManager.FXMSessionIdManagerProcessor, Sitecore.FXM" />
</getSessionIdManager>
This pipeline allows to dynamically select a Session ID Manager for the request. In the default Sitecore configuration, a non-default Session ID Manager will be used only for requests with explicit sessionId URL parameter, i.e. for FXM requests only.
For all other requests, no Session ID Manager will be explicitly selected, and the default System.Web.SessionState.SessionIDManager will be used; this is reflected in the warning message you're seeing. There is nothing wrong with this situation per se, this is by default and by design.
Seeing the message as an error on every page request
This definitely sounds like a defect to me. This message is supposed to be logged once per application lifetime instead of being thrown as an exception on every page.
You should report this to Sitecore support.
An attempt to fix
I cannot debug your system, so I have to do this blindfolded. I would try to create you own Session ID Manager selector:
public class CustomSessionIdManagerProcessor
{
public void Process(GetSessionIdManagerArgs args)
{
if(args.SessionIdManager == null)
{
args.SessionIdManager = new System.Web.SessionState.SessionIDManager();
}
}
}
Configure it as the last processor in the getSessionIdManager pipeline. This will make sure that there is always an explicitly selected Session ID Manager and should hopefully prevent the error from happening.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<getSessionIdManager>
<processor type="YourNamespace.CustomSessionIdManagerProcessor, YourAssembly" />
</getSessionIdManager>
</pipelines>
</sitecore>
</configuration>
In case it helps anyone else, we were running into this issue as well after upgrading to Sitecore 8.1 rev. 151003.
In our particular case the issue was with a namespace change in this line in the Web.config:
<sessionState mode="InProc" cookieless="false" timeout="20"
sessionIDManagerType="Sitecore.FXM.SessionManagement.ConditionalSessionIdManager">
That should be the following:
<sessionState mode="InProc" cookieless="false" timeout="20"
sessionIDManagerType="Sitecore.SessionManagement.ConditionalSessionIdManager">
It might have been something we missed in the upgrade guide, but we finall found it after pulling down the a copy of Sitecore 8.1 rev. 151003.zip from the downloads page.

enterprise library 3.1 - if one listener is failed then subsequent listener will be never executed

I am using Msmqdistributor service of Enterprise Library 3.1 to distribute logs from various application.I have defined multiple listeners in categorySources/specialSources, but if one listener is failed than subsequent listeners will be never executed.
Following is my config code.
<specialSources>
<allEvents switchValue="Warning" name="All Events">
<listeners>
<add name="Database Listener A" />
<add name="Custom Trace Listener A" />
<add name="Custom Trace Listener B" />
</listeners>
</allEvents>
<notProcessed switchValue="Warning" name="Unprocessed Category" />
<errors switchValue="Warning" name="Logging Errors & Warnings"/>
</specialSources>
If I am specifying wrong connection string for Database Listener A then it will be failed to insert logs in database. But it also stops the jobs of next Custom Trace Listener A and Custom Trace Listener B.So here Custom Trace Listener A and Custom Trace Listener B will be never executed if Database Listener A is failed.
Anybody can help please ?
Thanks
Mitesh Patel
This behavior seems to be "by design". See the answer for Microsoft Enterprise Library 4.1 Logging Fails on Windows XP SP3.
Of course, this doesn't really help you. One workaround would be to attach one listener to a category. So for your 3 listeners you could add 3 categories. This will work but is not particularly elegant.
Since you indicate that you are using 2 custom trace listeners another approach to mitigate the issue would be to code the custom trace listeners to swallow any exceptions (not usually a good idea, though). You could also order your trace listeners from least likely to fail to most likely to fail. E.g. Database > Event Log > Flat File. In your scenario place the custom trace listeners before the database trace listener.
It is also good practice to add a trace listener to the errors category. Not sure if you have that in your app or not (but the posted config doesn't).

WCF Web Service Metadata Publishing Disabled Error

I modified my web.config to add a custom binding in order to increase the buffer and message size, and it seems like in creating the service element explicitly, it has somehow broken the reference to my behavior element.
When I try to run my web service from VS using the WCF Test Client, or I go to the service page, I get the error:
Metadata publishing for this service is currently disabled.
I've compared my web.config to a few different sources on this and everything seems to match. I've no idea what the issue is.
Here is the System.serviceModel element:
<system.serviceModel>
<services>
<service name="BIMIntegrationWS.BIMIntegrationService" behaviorConfiguration="metadataBehavior">
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="http://localhost:1895/BIMIntegrationService.svc"
binding="customBinding" bindingConfiguration="customBinding0"
contract="BIMIntegrationWS.IBIMIntegrationService"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="customBinding0">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="262064"
maxBufferSize="262064"
maxBufferPoolSize="262064" />
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
It almost seems like either the web service page is not finding the element. I don't get an error complaining that the target behaviorConfiguration doesn't exist, or anything like that, just that Metadata publishing is not enabled.
Any help would be greatly appreciated.
Thanks.
I think i've "fixed" the issue. More coming later.
EDIT:
In order to "fix" my issue, I basically added a new WCF service to my application, and had it implement my previous interface, I then copied all the code from my original service and when I tweaked the .config file (to look pretty much like the one posted in the question), everything worked fine.
Ofcourse, I know, like we all know, that there is no magic here, that there must be some discrepancy. This is when I noticed/remembered, that after I had created my original service, called "BIMIntegrationService.svc", I had decided that this was too long of a name, so I renamed/refactored my class to "BIMIntegrationWS". Doing this, however, does not change the name of the service file (and therefore the name of the file in the http:// address).
Long story short, I made 2 changes to my .config and everything worked:
1) I changed:
<service name="BIMIntegrationWS.BIMIntegrationService" behaviorConfiguration="metadataBehavior">
to
<service name="BIMIntegrationWS.BIMIntegrationWS" behaviorConfiguration="metadataBehavior">
After running the service like this, I got an error (a helpful one this time) complaining that if multipleSiteBindings was enabled, the endpoint address had to be relative. So:
2) I set that to false (because I don't remember why it was in there in the first place) and everything worked fine.
I guess I should have taken a hint when it seemed like my web service was not using my "service" element at all. :\
EDIT 2:
Actually, you can see in my second comment, in the original question, that the auto-generated tag was pointing to: , as opposed to "BIMIntegrationService".
That should have given it away.
I doubt many other people will have this same issue, but just in case.
I've had the same trouble; I've gotten everything configured correctly (even copied the code from a previous service I have running) and yet no change on allowing the service to expose metadata. yet, if I make a spelling error, parse error, etc. to the app.config I'm given exceptions telling me to correct the problem (which tells me the service is reading the config, just disregarding it.
I was able to bypass it by generating the config settings in the host application:
System.ServiceModel.Description.ServiceMetadataBehavior smb = new System.ServiceModel.Description.ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
ServiceBase host = new Servicebase(typeof(MyService), new Uri("http://localhost:1234/"));
host.Description.Behaviors.Add(smb);
host.Open();
...
host.Close();
Basically allow the code to override and push the config file changes i wanted applied. I know it's not ideal, but I was exposing the service through a windows service which made this do-able. if you do get your problem resolved, please pass along the solution though as I'd be curious to know why (at least in yours, if not both our cases) it's failing.