Every once and while you run into a silly bug that actually takes you a long time to figure out. Some time ago I ran into a problem with a custom SPDiagnosticServiceBase class that only surfaced via PowerShell.
Let’s take a closer look at the problem…
First, we start out by creating a custom diagnostic logging class that contains multiple categories. When it’s properly deployed, we’d see custom area ("Test Area") and all of the categories in Central Admin. Through the Diagnostic Logging page, you’d find you can change the throttle limits like any other out of box category.
Now, let’s open up a PowerShell console and try to change one of the categories using Set-SPLogLevel.
This commandlet allows you to specify the area and category using a very simple Area:Category format. In a simpler fashion, if you specify a string with no colon, the value you provide is treated as a category.
In the next screenshot, you can see that I am trying to set the TraceSeverity to Verbose for category "dddd". Note the error that is returned!
Huh?! Didn’t I just see that category in Central Admin? How about if I try the more generic Area:Category format with a wildcard? Same result!
I shot an email off to my teammate Gary Lapointe, who knows all things PowerShell, and a group of SharePoint Masters. No luck. No one apparently has seen this problem. This was going to be just one of those days…
The biggest clue popped out when I tried using the most generic form of Set-SPLogLevel. If you don’t specify an Identity parameter (for example: "Set-SPLogLevel -TraceSeverity Verbose"), Set-SPLogLevel sets the provided value to all categories. However, for our custom diagnostic class, what do you see?
SP was seriously getting confused. Three problems jumped out: Trace Severity was set to the wrong value (None instead of Verbose), Event Severity was improperly changed to "Error", and finally only the first category was updated.
To make a long debugging story short, I finally was able to isolate and fix the problem!
My problems all arose from how I initialized the categories themselves. If you call the simplest constructor (as I did and most likely a lot of other folks!), your code would look like …
The real tricky part to isolating the problem is that you need to set the log levels via PowerShell first. If you set the log level via Central Admin, the problem is mostly hidden.
Use the SPDiagnosticsCategory constructor that takes four parameters.
In particular, specify a value for the category id. The updated initialization block looks like…
In my example, the id value is coming from an enum that is used for categorization of the items written to the diagnostic service. This could have easily been as simple as an incrementing counter (0, 1, 2, etc).
Be sure to start the value sequence at 0. I eventually found that if you want to start your ID values at something other than 0, you’ll eventually run into the same problem.
With the SPDiagnosticCategory initialized in this fashion, setting the log levels via PowerShell will work as expected.