Let us imagine
that you've done a bad. Or, more easily imagineable, that a colleague has. SharePoint has presented you with a "Woopsie! And here's the
correlation id: {27B94581-9972-4D93-AD7F-DDCB72EF0FA1}".
If you've ever
developed with SharePoint, you know what I'm talking about…
So you navigate to
the SharePoint hive, find the logs directory, sort by date, open the newest
file in notepad, and search for the error. Or if you're black belt you use
UlsViewer and, well, basically do the same.
But after you've
developed with SharePoint a bit, you decide to get certified, and find that one
of the questions has an answer that must be correct (the others being
non-sensical) which mentions Get-SPLogEvent.
How does that work?
Well, the Get-Help Get-SPLogEvent -Examples
works as usual.
Basic idea:
Get-SPLogEvent
-StartTime "13/11/2012 08:38:23" -EndTime "13/11/2012
08:38:23.02"
finds all the errors
between start and end times.
And if you only want to see your colleague's error you filter by correlation ID:
Get-SPLogEvent
-StartTime "13/11/2012 08:38:23" -EndTime "13/11/2012
08:38:23.02" | Where-Object { $_.Correlation -eq
'{27B94581-9972-4D93-AD7F-DDCB72EF0FA1}'}
You may be tempted
to forego the start and end times. Do not do this. Well, ok, do it just this
once. And start task manager first - it is always nice to watch all those cores
getting a proper work out.
Having to type the
start and end time quickly gets tiresome.
On a dev box it
makes sense to use a starttime of five or ten minutes ago (i.e. Now.AddMinutes( -5/-10)). And you don't really need EndTime.
$events =
Get-SPLogEvent -StartTime (Get-Date).AddMinutes(-10) | ? { $_.Correlation -eq
'{27B94581-9972-4D93-AD7F-DDCB72EF0FA1}'}
...so you wrap this in a Powershell snippet which takes an argument, and you're happy.
Or not.
I hate pasting into
command windows, even if it's set up as right-click to paste.
So. How about a tiny
a win64 application? With a textbox? Paste the correlation id into that
textbox, create a Powershell script on the fly, and call it.
Better.
But it can be
improved. How about... A tiny application that has a GotFocus handler. And
checks the clipboard - if it's a guid, grab it, create the script, and
call it. In a background thread, so we're still (almost) responding to stuff:
private BackgroundWorker _worker;
public LogForm()
{
InitializeComponent();
_worker = new BackgroundWorker {WorkerSupportsCancellation = false, WorkerReportsProgress = false};
_worker.RunWorkerCompleted += (sender, e) =>
{
Cursor = Cursors.Default;
if (e.Error != null)
{
feedbackTextBox.Text = "Error: " + e.Error.Message;
}
else
{
resultTextBox.Text = e.Result.ToString();
}
};
_worker.DoWork += (sender, e) =>
{
var script = e.Argument as string;
var result = RunPowershell(script);
e.Result = result;
};
}
private void LogForm_Enter(object sender, EventArgs e)
{
if (Clipboard.ContainsText() && !_worker.IsBusy)
{
var text = Clipboard.GetText().Trim();
Guid correlationId;
try
{
correlationId = new Guid(text);
}
catch (FormatException ex)
{
return; // not a guid. (there is no Guid.TryParse)
}
correlationTextBox.Text = correlationId.ToString("B");
resultTextBox.Text = string.Empty;
feedbackTextBox.Text = string.Empty;
this.Cursor = Cursors.WaitCursor;
var script = string.Format(@"
$events = Get-SPLogEvent -StartTime (Get-Date).AddMinutes(-10) | ?{{$_.Correlation -eq '{0}'}}
foreach ($event in $events)
{{
$event.Message
}}
",
correlationId.ToString("B"));
Clipboard.Clear();
_worker.RunWorkerAsync(script);
}
}
The "runpowershell" method is largely unchanged from a previous post:
public string RunPowershell(string powershellText)
{
// Powershell ~= RunspaceFactory - i.e. Create a powershell context
var runspace = RunspaceFactory.CreateRunspace();
var resultString = new StringBuilder();
try
{
// load the SharePoint snapin - Note: you cannot do this in the script itself (i.e. add-pssnapin etc does not work)
PSSnapInException snapInError;
runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out snapInError);
runspace.Open();
var pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(powershellText);
// add a "return" variable
pipeline.Commands.Add("Out-String");
// execute!
var results = pipeline.Invoke();
// convert the script result into a single string
foreach (PSObject obj in results)
{
resultString.AppendLine(obj.ToString());
}
}
finally
{
// close the runspace
runspace.Close();
}
// consider logging the result. Or something.
return resultString.ToString();
}
Awesome.
It should, perhaps, be mentioned that just as I was putting the finishing touches on this post, VS 2012 update 1 was released - which includes improved SharePoint integration, especially w.r.t. SharePoint logs.
To summarise: We created a tiny application which automatically searches the SharePoint logs for a clipboarded correlation guid.