Sandboxed logging part 1   

Tags: SharePoint 2010, PowerShell
Technorati Tags: ,

I’m learning how I can improve my coding skills by using Patterns and practices(PP) and I learned how easy it was with PP to log within sandboxed solutions to the event viewer. unfortunately this doesn’t work for SharePoint 365 but don’t worry I also have a “little fix” for that.

 

I uploaded an example that you can use at our codeplex site. If you open the zip file you will see the following folder and files. It is recommended to download the example because the necessary wsp and DLL are also in the zip file :).

 

image

 

 

Diagnostics area

 

First thing we need to do is create a custom diagnostics area where we can log to. When your creating a diagnostic area it is also advised to create categories.

 

I used an xml file that will be the base of creating the areas and categories. In this example where only going to add new areas and categories how to remove areas and categories you can read it at the PP site.

 

XML File

<Areas>
    <ADD>
        <Name>VNTG</Name>
        <Categories>
            <Category>Debug</Category>
            <Category>Workflow</Category>
            <Category>Feature</Category>
            <Category>Webpart</Category>
        </Categories>
    </ADD>
</Areas>

 

The Code

 

You can create diagnostics areas with a SharePoint feature or you can use a Console application. In this example I’m going to use a console application.

 

Step 1.

Create a new Console application and name it “CreateEventSources”.

image

 

Step 2.

Put the platform target to “x64”.

image

 

Step 3.

Refenrence the following DLL files “Microsoft.Practices.ServiceLocation”,”Microsoft.Practices.SharePoint.Common”. The DLL files can be found in the zip file you downloaded from our codeplex.

image

 

Step 4.

Set the DLL files to “Copy Local” = true.

image

 

Step 5.

Reference the SharePoint DLL.

 

Step 6.

Use the following classes.

using Microsoft.Practices.SharePoint.Common.Logging;
using System.Diagnostics;
using Microsoft.Practices.SharePoint.Common;
using Microsoft.SharePoint;
using Microsoft.Practices.SharePoint.Common.Configuration;
using Microsoft.Practices.SharePoint.Common.ServiceLocation;
using Microsoft.Practices.ServiceLocation;

 

Step 7.

Copy past the code :).

class Program
{
    static void Main(string[] args)
    {
        if (args.Length >= 2)
        {
            List<string> paramaters = new List<string>();
            paramaters.Add("ADD");
            paramaters.Add("REMOVE");
            paramaters.Add("SEARCH");
 
            string operation = args[0].Trim();
 
            if (paramaters.Contains(operation.ToUpper()))
            {
                string siteURl = args[1].Trim();
 
                IServiceLocator serviceLocator = SharePointServiceLocator.GetCurrent();
                IConfigManager config = serviceLocator.GetInstance<IConfigManager>();
 
                using (SPSite site = new SPSite(siteURl))
                {
                    config.SetWeb(site.RootWeb);
                    DiagnosticsAreaCollection areaCollection = new DiagnosticsAreaCollection(config);
                    string areaName = string.Empty;
                    string categoryName = string.Empty;
 
                    if (operation.ToUpper() == "ADD" && args.Length >= 4)
                    {
                        areaName = args[2];
                        categoryName = args[3];
 
                        AddArea(areaCollection, areaName, categoryName);
                        DiagnosticsAreaEventSource.EnsureConfiguredAreasRegistered();
                    }
 
                    if (operation.ToUpper() == "REMOVE" && args.Length >= 3)
                    {
                        areaName = args[2];
                        if (args.Length >= 4)
                        {
                            categoryName = args[3];
                        }
                        if (string.IsNullOrEmpty(categoryName))
                        {
                            RemoveArea(areaCollection, areaName);
                            if (EventLog.SourceExists(categoryName))
                            {
                                EventLog.DeleteEventSource(categoryName);
                            }
                        }
                    }
 
                    Console.WriteLine("Event Log: Event Log Name = {0}; Exist = {1}",
                        Constants.EventLogName, EventLog.Exists(Constants.EventLogName));
 
                    foreach (DiagnosticsArea item in areaCollection)
                    {
                        Console.WriteLine("Event Log: Area Name = {0}; Exist = {1}",
                            item.Name, EventLog.SourceExists(item.Name));
                        Console.WriteLine("SP: Area Name = {0}; Category Count = {1}",
                            item.Name, item.DiagnosticsCategories.Count.ToString());
 
                        if (item.DiagnosticsCategories.Count > 0)
                        {
                            int categoryIndex = 0;
 
                            foreach (DiagnosticsCategory category in item.DiagnosticsCategories)
                            {
                                Console.WriteLine("\tCategory[{0}] Name = {1}", categoryIndex++, category.Name);
                            }
                        }
                    }
                    return;
                }
            }
        }
        Console.WriteLine("Parameters Error.");
    }
 
    private static void RemoveArea(DiagnosticsAreaCollection areas, string areaName)
    {
        if (IsExistArea(areas, areaName))
        {
            while (areas[areaName].DiagnosticsCategories.Count != 0)
            {
                areas[areaName].DiagnosticsCategories.Clear();
            }
            areas.RemoveAt(areas.IndexOf(areas[areaName]));
            areas.SaveConfiguration();
        }
    }
 
    private static void AddArea(DiagnosticsAreaCollection areaCollection, string areaName, string categoryName)
    {
        if (!IsExistArea(areaCollection, areaName))
        {
            DiagnosticsArea newArea = new DiagnosticsArea(areaName);
 
            newArea.DiagnosticsCategories.Add(new DiagnosticsCategory(categoryName));
            areaCollection.Add(newArea);
        }
        else
        {
            int index = areaCollection.IndexOf(areaCollection.First(o => o.Name.Equals(areaName)));
 
            if (areaCollection[index].DiagnosticsCategories.Count(o => o.Name.Equals(categoryName)) == 0)
            {
                areaCollection[index].DiagnosticsCategories.Add(new DiagnosticsCategory(categoryName));
            }
        }
        areaCollection.SaveConfiguration();
    }
 
    static private bool IsExistArea(DiagnosticsAreaCollection collection, string areaName)
    {
        foreach (DiagnosticsArea item in collection)
        {
            if (item.Name.Trim().ToUpper() == areaName.Trim().ToUpper())
                return true;
        }
        return false;
    }
 
    static private void RemoveCategory(DiagnosticsAreaCollection areas, string areaName, string categoryName)
    {
        if (IsExistArea(areas, areaName))
        {
            DiagnosticsArea currentArea = areas[areaName];
            if (currentArea.DiagnosticsCategories.Count != 0 &&
                currentArea.DiagnosticsCategories.Count(o => o.Name.Equals(categoryName,
StringComparison.OrdinalIgnoreCase)) > 0)
            {
                int index = currentArea.DiagnosticsCategories.IndexOf(
                    currentArea.DiagnosticsCategories.First(o =>
                        o.Name.Equals(categoryName, StringComparison.OrdinalIgnoreCase)));
                currentArea.DiagnosticsCategories.RemoveAt(index);
            }
            areas.SaveConfiguration();
        }
    }
}

 

Step 8.

Create a folder where you will add all the necessary files to deploy and install the diagnostics logging. You can find the wsp files in my zip file. After you build the the console application copy paste the exe file to the folder CreateEventSources.

 

image

 

Step 9.

Create a powershell script to deploy the necessary wsp’s and to install the diagnostics areas with the xml file and console application. Name the powershell script “EnableSandboxedLoging.ps1”.

 

Step 10.

The powershell code.

Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue
 
#function that will check the job status of the solution.
function WaitForJobToFinish([string]$SolutionFileName)
{ 
    $JobName = "*solution-deployment*$SolutionFileName*"
    $job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
    if ($job -eq $null) 
    {
        Write-Host 'Timer job not found'
    }
    else
    {
        $JobFullName = $job.Name
        Write-Host -NoNewLine "Waiting to finish job $JobFullName"
        
        while ((Get-SPTimerJob $JobFullName) -ne $null) 
        {
            Write-Host -NoNewLine .
            Start-Sleep -Seconds 2
        }
        Write-Host  "Finished waiting for job.."
    }
}
 
 
if ($args.Length -ge 1)  {
#get the sharepoint url
$url = $args[0];
 
#create the solution path
$solutionPath = [string]::Concat($PWD.Path,"\wsp\");
 
#configurationproxy wsp name
$configurationproxy = "configurationproxy.wsp";
 
#Logerproxy wsp name
$loggerproxy = "Microsoft.Practices.SharePoint.Common.LoggerProxy.wsp";
 
Write-Host -ForegroundColor Green "adding and installing $configurationproxy and $loggerproxy";
 
Add-SPSolution  "$solutionPath$configurationproxy";
Add-SPSolution  "$solutionPath$loggerproxy";
 
Install-SPSolution $configurationproxy -GACDeployment -Force;
WaitForJobToFinish($configurationproxy)
 
Install-SPSolution $loggerproxy -GACDeployment -Force;
WaitForJobToFinish($loggerproxy)
 
#fetch the xml data
[Xml]$xmlFile = Get-Content "Areas.xml"
 
#Loop the ADD elements to add the diagnostics areas and categories
Foreach($add in $xmlFile.Areas.ADD){
    Write-Host -ForegroundColor Green $add.Name
    
    foreach($cat in $add.Categories.Category){
        & ".\CreateEventSource\CreateEventSource.exe" "ADD" $url $add.Name $cat;
    }
}
}
 

 

Step 11.

You can run the PowerShell script with the following command.

.\ EnableSandboxedLoging.ps1 “http://urlofyoursharepointsite”

 

Step 12.

Check if the the following features are activated. The features can be found at the Farm Features.

image

 

Tip: If you are using multiple frontend servers you have to create a console application that executes the following line of code.

DiagnosticsAreaEventSource.EnsureConfiguredAreasRegistered();

Then you are sure that on all frontend servers the the areas and categories are created. You can also create a timer job that only runs one time to execute that command.

Part 2: Example webpart sandbox logging

 
Posted by  Gilissen Timmy  on  12/26/2011
0  Comments  |  Trackback Url  | 0  Links to this post | Bookmark this post with:        
 

Links to this post

Comments

Name *:
URL:
Email:
Comments:


CAPTCHA Image Validation