Tuesday, February 26, 2008

New times... new blog

Recently I was offered a new position in Pentia. The position was as "Core Technology Specialist" in a new department of Pentia (called The Core Team). I accepted and started my new work last week.
The department is responsible for several things stretching from technical presales to architecture to development of tools, that the developers in Pentia can use. As a part of these new task me and my coworker in the Core Team - Thomas Eldblom - decided to create a shared blog. Its placed here: http://mcore.wordpress.com/
The goal of this blog is to share our knowledge and findings about Sitecore to other co-workers in Pentia, but also externally to all other Sitecore users. The blog is going to hold our biased opinions on Sitecore, and not as much technical walkthroughs. Take a look...

Tuesday, January 22, 2008

Logs and performance

I was recently assigned to monitor and report on some issues with performance. I was told to log some information about how long different requests on pages took. Here I stumbled upon two things that I didn’t find all that well documented on SDN5.

1. Logging with log4net. I needed a separate log file, as I didn’t want all my entries to mess up the standard log file.
2. There are performance counters in Sitecore, but I didn’t know where I could find these.

So I thought I’d just report my findings on my blog to the help of others.

Creating a separate log in log4net is actually quite simple. Go to the log4net section in the web.config. Here you can add a new appender that writes to a separate file:

  <appender name="PerformanceFileAppender" type="log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging">
    <file value="D:/MyPath/Data/logs/Performance.{date}.txt" />
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="DEBUG"/>
      <levelMax value="DEBUG"/>
    <appendToFile value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-21t %d %-5p %m%n" />

If you look at the LevelRangeFilter, you’ll see, that you can specify a min and max level. There are different levels and you can specify which levels to write to the given logfile. The level ranges from DEBUG to FATAL. There are as default these levels: ALL, DEBUG, INFO, WARN, ERROR, FATAL.
In this case I only want the DEBUG information written and keep that level out of the Sitecores log file. Therefore I changed the Sitecore appender to range from the level INFO to FATAL:

  <appender name="LogFileAppender" type="log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging">
    <file value="D:/MyPath/Data/logs/log.{date}.txt" />
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="INFO"/>
      <levelMax value="FATAL"/>
    <appendToFile value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-21t %d %-5p %m%n" />

I then altered the root element to include my appender and altered the level requirements to ALL:

    <priority value="ALL" />
    <appender-ref ref="LogFileAppender" />
    <appender-ref ref="PerformanceFileAppender" />

Now I can write to my custom log file by using the ILog interface and use the method Debug:

ILog perfLog = LogManager.GetLogger("PerformanceFileAppender");
perfLog.Debug(”Hello world!”);

You can read more about it at log4nets page. Here you can also read about different types of appenders and much more.

So now I had a log I could use for debugging. Now I just needed the performance counters. So I looked at the HttpRequestBegin pipeline. There I found a processor called StartMeasurements. Thanks to Lutz Roeder’s Reflector I found that Sitecore starts a timer and stores it like this:

Context.Items["SC_REQUEST_MEASUREMENT_TIMER"] = new HighResTimer(true);

And the requested URL like this:

Context.Items["SC_REQUEST_MEASUREMENT_URL"] = args.Context.Request.RawUrl;

Now all I had to do, was to hook in on the httpRequestEnd pipeline and add my own processor that would log the time elapsed. So I added this just before the StopMeasurements processor:

<processor type="MyNameSpace.MeasurementLogger, MyNameSpace">

I then created a new class and added the debug logging:

public class MeasurementLogger
  #region private properties
  private static readonly ILog perfLog = LogManager.GetLogger("PerformanceFileAppender");

  public class MeasurementLogger
    #region private properties
    private static readonly ILog perfLog = LogManager.GetLogger("PerformanceFileAppender");

    public void Process(HttpRequestArgs args)
      HighResTimer timer = Sitecore.Context.Items["SC_REQUEST_MEASUREMENT_TIMER"] as HighResTimer;
      string timeElapsed = timer.Elapsed().ToString();
      string requestedUrl = Sitecore.Context.Items["SC_REQUEST_MEASUREMENT_URL"] as string;

      perfLog.Debug("HTTPRequest time: " + timeElapsed + " Url: " + requestedUrl + " Domain: " + args.Context.Request.Url.Host);

And that’s it. Now you’ll write the elapsed time on all requests to the performance.{date}.txt log file.
Some might see this as overkill, as you can use the stats.aspx or IIS log files etc., but none the less this gives an introduction using log4net as well as hooking into a pipeline.

There will come more posts about relational data, I just haven’t finished them yet.

Tuesday, December 18, 2007

Relational Data 1 - Indexing

All though a bit late (been quite busy), here is the first post about relational data.
As I described you might want to do some relational operations on data structured as a hierarchy in Sitecore. The example was news which might need to be sorted and listed on the frontpage or similar, is the one I am going to address first.

Most of the times when I stumble upon issues like this, I solve it with indexing. That is building a relational data set from the hierarchy. When working for clients, most of the times I have solved this issue using Ankiro. However Ankiro cost money, so I thought I would try it out with Lucene. Below you can see an example of how to do this.

Please note that by default Lucene doesn’t index on publish, but by a scheduled task that as default runs every five minute. However it is possible to customize Lucene to index on the publish event.

Well here it the technical description:
First of all you need to create the index containing the data you want to use as relational data. This is done pretty easy in web.config. Further reading is available on SDN (

Basically you define the index in the <indexes> element :

<index id="newsIndex" singleInstance="true" type="Sitecore.Data.Indexing.Index, Sitecore.Kernel">
  <param desc="name">$(id)</param>
<index id="newsIndex" singleInstance="true" type="Sitecore.Data.Indexing.Index, Sitecore.Kernel">
  <param desc="name">$(id)</param>
  <templates hint="list:AddTemplate">
    <!-- Enter the id of your news template -->
  <fields hint="raw:AddField">
    <!-- add the fields you want in your index -->
    <field target="created">__created</field>
    <field target="updated">__updated</field>
    <field target="author">__updated by</field>
    <field target="published">__published</field>
    <field target="name">@name</field>
    <field target="id">@id</field>
    <field target="Title">Title</field>
    <field target="Abstract">Abstract</field>
    <field target="Release date">Release date</field>

This defines the index. Now add it to the web database:

<database id="web" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
  <indexes hint="list:AddIndex">
    <index path="indexes/index[@id='newsIndex']"/>

You can now rebuild indexes for the web database through the Control Panel in Sitecore.

Now that you have the index, you can do you relational operations. For instance you might want to sort by date. Here is some sample code to retrieve an arbitrary number of news items from the index sorted by the “Release date” field. (I don’t like to use the system fields __updated or __created as these might change when you upgrade or similar).

public Document[] GetLatestNews(int numberOfNews)
  //Get the Lucene IndexSearcher
  Index newsIndex = Sitecore.Configuration.Factory.GetIndex("newsIndex");
  Database web = Sitecore.Configuration.Factory.GetDatabase("web");
  IndexSearcher searcher = newsIndex.GetSearcher(web);

  //I want to sort by the release date
  Sort sort = new Sort("Release date",true);

  //I want all documents that has the field Release date
  Query searchingxml = new WildcardQuery(new Term("Release date", "*"));

  //Get all the hits sorted
  Hits hits = searcher.Search(searchingxml, sort);

  //How many documents should be returned
  int noOfNews = hits.Length() > numberOfNews ? numberOfNews : hits.Length();
  Document[] docs = new Document[noOfNews];

  //Iterate over the hits and return the number of news I want as documents
  for (int i = 0; i < noOfNews; i++)
    docs[i] = hits.Doc(i);
  return docs;

This returns the latest news, which you can list in your spot or whatever you want to do.

The advantages of using index’ is:
You got the advantages of a hierarchy in the backend.
The end user doesn’t feel or see any other technology then Sitecore.
It is simple and easy to implement and maintain.

The disadvantages of using index’ is:
It is replicated data. This takes up more space and I often find problems with inconsistency between index’ and Sitecore data.
You got the disadvantages of a hierarchy in the backend.

Sunday, September 30, 2007

Relational data in Sitecore - Intro

Content and data in Sitecore are structured as a hierarchy. This gives a lot of advantages, but sometimes you got some relational data, that you fit into a Sitecore structure. This has some disadvantages. First of all the relational data might not be user friendly and intuitively structured, when saved in a Sitecore database. Secondly some operations that you need to perform on the data might be extremely slow, when structured as a hierarchy.

A good example of this, is something I have done on almost every solution: News and news lists. This can be structured as a hierarchy in the backend, but often requires operations on the frontend, that only performs, when the data is in a table. Something that is very normal is a front page spot, which lists the X number of latest news of a special type. This would normally require you to iterate over all items in your content structure, which doesn’t perform unless your site consist of very few nodes.

In a couple of posts on this blog, I will try and show some different solutions to the problem.

Happy reading!

Wednesday, September 12, 2007

Getting an items rendering

Often you need to get the rendering(s) used to render a given item from a codebehind. You want to get the rendering, that the rendering engines uses. That means, that if there isn't a rendering on the item, you should look at the template and so forth.
I spent some time figuring out, how this is done (I actually ended up asking Sitecore Support), so I thought I would just share it with you:

/*First you need the item you want the renderings from. In this case lets use the current Item */
Sitecore.Data.Items.Item item = Sitecore.Context.Item;
/*We also need the device, so we get the renderings attached to that. */
Sitecore.Data.Items.DeviceItem device = Sitecore.Context.Device;

/*This is how you get the rendering */
Sitecore.Layouts.RenderingReference[] renderings = item.Visualization.GetRenderings(device, true);

This is actually pretty simple,which might be the reason for me not figuring it out. ;)
As you now have an array of RenderingReference, you can look up the rendering by its ID or whatever.

Monday, July 23, 2007

SQL restore/backup script

Well I haven't been active on this blog lately. The reason is that I have been working on Sitecore upgrades the last couple of months (well it feel like years), so I haven't stumbled upon any tweaks or tricks.
One thing that has been handy though, is these SQL scripts for back up and restoring Sitecore databases. It seems one will be doing that alot during upgrades. They were made by my collegue Alan Coates.


BACKUP database <prefix>_Archive
TO DISK = 'E:\backup\<filename>.bak'
BACKUP database <prefix>_Core
TO DISK = 'E:\backup\<filename>.bak'
BACKUP database <prefix>_Extranet
TO DISK = 'E:\backup\<filename>.bak'
BACKUP database <prefix>_Master
TO DISK = 'E:\backup\<filename>.bak'
BACKUP database <prefix>_RecycleBin
TO DISK = 'E:\backup\<filename>.bak'
BACKUP database <prefix>_Security
TO DISK = 'E:\backup\<filename>.bak'
BACKUP database <prefix>_Web
TO DISK = 'E:\backup\<filename>.bak'

RESTORE DATABASE <prefix>_Archive FROM DISK = 'E:\Backup\<prefix>_Archive.bak'
MOVE 'scCore_Data' TO 'E:\<sqldata>\<prefix>_Archive.mdf',
MOVE 'scCore_Log' TO 'E:\<sqldata>\<prefix>_Archive_log.ldf'
RESTORE DATABASE <prefix>_Core FROM DISK = 'E:\Backup\<prefix>_Core.bak'
MOVE 'scCore_Data' TO 'E:\<sqldata>\<prefix>_Core.mdf',
MOVE 'scCore_Log' TO 'E:\<sqldata>\<prefix>_Core_log.ldf'
RESTORE DATABASE <prefix>_Extranet FROM DISK = 'E:\Backup\<prefix>_Extranet.bak'
MOVE 'nextOT_Data' TO 'E:\<sqldata>\<prefix>_Extranet.mdf',
MOVE 'nextOT_Log' TO 'E:\<sqldata>\<prefix>_Extranet_log.ldf'
RESTORE DATABASE <prefix>_Master FROM DISK = 'E:\Backup\<prefix>_Master.bak'
MOVE 'scCore_Data' TO 'E:\<sqldata>\<prefix>_Master.mdf',
MOVE 'scCore_Log' TO 'E:\<sqldata>\<prefix>_Master_log.ldf'
RESTORE DATABASE <prefix>_RecycleBin FROM DISK = 'E:\Backup\<prefix>_RecycleBin.bak'
MOVE 'scCore_Data' TO 'E:\<sqldata>\<prefix>_RecycleBin.mdf',
MOVE 'scCore_Log' TO 'E:\<sqldata>\<prefix>_RecycleBin_log.ldf'
RESTORE DATABASE <prefix>_Security FROM DISK = 'E:\Backup\<prefix>_Security.bak'
MOVE 'nextOT_Data' TO 'E:\<sqldata>\<prefix>_Security.mdf',
MOVE 'nextOT_Log' TO 'E:\<sqldata>\<prefix>_Security_log.ldf'
RESTORE DATABASE <prefix>_Web FROM DISK = 'E:\Backup\<prefix>_Web.bak'
MOVE 'scCore_Data' TO 'E:\<sqldata>\<prefix>_Web.mdf',
MOVE 'scCore_Log' TO 'E:\<sqldata>\<prefix>_Web_log.ldf'

Monday, February 19, 2007

Cleanup html with one button click

It is possible to create your own buttons in the rich text editor. This can be used to create your own functionality. For instance I recently had to make a button that cleans up the HTML entered in a rich text field. Now this functionallity is allready present in Sitecore, but it is devided into 5 steps. E.g. remove font tags, remove span tags etc.
In this particullar case we wanted a button to perform a cleanup tasks, that included three of these methods. Instead of clicking three times to remove font tags, css styling and word formatting, we needed to create a button that did all of these tasks, by clicking one time only. This can be done by:

Step 1:
Create the button in Sitecore. The buttons for the editor is found in here: Sitecore > System > Settings > Html Editor Profiles > Rich Text Default > Toolbar X.
Now copy an existing button and rename it to what ever you like. In this instance we'll call it CustomCleanup. In the field "Click" you can enter a string, that will be fired when the button is clicked. You can later catch when this message is fired. Put in what ever string you like. In this case we'll enter "CustomCleanupTask".

Step 2:
Now we need to catch the message. This is done in the javascript file: sitecore/shell/Controls/Rich Text Editor/RichText Commands.js. Now add the following to the file:

RadEditorCommandList["CustomCleanupTask"] = function(commandName, editor, tool) {

/* Fire new events */


P.s. you can alter the icon on the button, by adjusting the Icon field on the button. This path is taken from /sitecore/shell/RadControls/Editor/Skins/*/Buttons

Now you have your new functionality. Remember to clear the cache.