Archive for Logging

We have a lot of customers using Gibraltar with the server-side Silverlight apps, but until now, you had to roll your own solution to get client-side log messages into Gibraltar.  There were options such as using NLog or CLog to forward client-side messages to Gibraltar, but we didn’t provide any out-of-the-box capability for client-side logging.

We’ve just released sample code (both source and binary) that will ultimately form the basis for built-in Silverlight and Windows Phone support in a future version of Gibraltar.  It supports Silverlight 3 & 4 as well as Windows Phone 7.x. You can use on binaries as-is (we even provide a NuGet package to make it super easy to integrate), or you can start with our implementation then tweak the code as you wish. Either way, it gives you an easy way to get a more complete picture from your Gibraltar logs today including both client- and server-side logging.

Please check out the bits and let us know what you think!

Understanding the Design
Our support for Silverlight comes in two parts: a client-side library that is a subset of the current Gibraltar.Agent shipping release, and a server-side AgentConnector that acts as the “message sink” for each Silverlight client that writes client-side messages to the Gibraltar log, which is then packaged up and pushed to the Hub and/or Analyst just as you would expect.

image

The Agent Connector is a REST-based WCF service that leverages WebActivator to automatically configure the service route, give you near-zero-config that will have you up and running in less than 5 minutes.

Log messages are continuously streamed from each client to your web application with client-side message buffering to ensure that no more than one outbound request to to the Agent Connector is active at once for each client. Server-side, each client is assigned a unique ID to make it easy to analyze multi-user behaviors and trace individual client sessions from Gibraltar Analyst.

Getting the Bits
There are two different ways you can get the code. The first is through NuGet.org. If you’re not familiar with NuGet, it is a free Visual Studio extension that manages assembly dependencies including automatic downloads and updates. The “Server” component of this design leverages NuGet to pull down Gibraltar.Agent, as well as WebActivator, so either way, you’ll want to check it out.

The second option is to download a zip file containing the same binaries included in the NuGet packages as well as the full source code, an end-to-end sample application and a ReadMe file with details on building and integrating the code.

Installing the Server Bits with NuGet
Your solution will likely have two parts, a Silverlight client app, and a Web Application. To start, you’ll want to have the NuGet Package Manager installed in VS2010. You’ll also want to have already configured the Gibraltar Agent on your web app. If you have not done so, please follow the directions on this page of our User’s Guide.

Right-click your web project, and select “Manage NuGet Packages”. In the resulting window, type “Gibraltar.Agent” into the search box in the top-right corner. You should be presented with a number of packages. Select ‘Gibraltar Agent for Silverlight – Server”. This will add the assembly references, as well as a clientaccesspolicy.xml file, to the root of your app. You can also open up the NuGet Package Console and type “Install-Package Gibraltar.Agent.Silverlight.Server”, which will accomplish the same thing.

Installing and Configuring the Client Bits with NuGet
Now right-click your Silverlight project, call up the NuGet Package Manager again, run the same search, and this time select the “Gibraltar Agent for Silverlight – Client” package. You can also open up the NuGet Package Console and type “Install-Package Gibraltar.Agent.Silverlight.Client”. After it installs the proper assemblies for your project type (the same package has the SL3, SL4, and WP7 binaries), there is one more thing you’ll need to do. You need to add the following string to the ResourceDictionary in your App.xaml file:

<system:String x:Key="GibraltarAgentServer">http://YOURSITEHERE.com/</system:String>

This value needs to be the root of your application, be it a domain, subdomain, or IIS application. This will be combined with the built-in WCF route auto-registered by the Server binaries (“/GibraltarAgentService/”, to be exact). Now, you should be able to use Gibraltar.Agent.Log just like you always have:

Log.TraceCritical("This is a critical message.");

Since multiple clients will likely be connected, the service assigns each IP address a unique integer ID, so you can easily track which messages come from which clients or have Gibraltar filter the view to only show messages from a single client. You’ll see results similar to the screenshot below:

image

Well, there you have it. Get the bits and tell us what you think. Even with this early sample, we’ve sought to make it as robust and forgiving as possible, in line with our goal to “First, Do No Harm”. Your feedback will help us extend and harden our Silverlight support and become an easy-to-use and rock-solid part of the standard distribution for a future Gibraltar version. So, if you find any issues, please do not hesitate to leave a comment and let us know.

Categories : .NET, CEIP, Logging, Silverlight
Comments (3)

One of the great things about coming to work for Gibraltar is learning about all of these things that I didn’t know the product could do. For example, the other day, I was asked in one of our Live Support chats about how to see the details of a web site session in progress.

Gibraltar collects a wealth of information about your running website. However, by default, you can’t analyze the data until the web server process completes.  I knew that live monitoring is one of the killer features slated for Gibraltar 3.0, but I didn’t realize that there are also very simple, workable ways to get Gibraltar data anytime you need it within the current Gibraltar 2.5 release.

As a former Gibraltar customer, when I wanted to get this data in the past, I simply recycled the AppDomain myself. I had Gibraltar configured to “autoSendSessions”, so whenever I recycled the AppPool, I’d automatically receive the latest logs.  I realize that is not the best answer for a number of reasons, but it is what worked for me, so I passed that suggesion to the customer.

A little later, our fearless leader Jay messaged me and asked why I hadn’t sent him the link to the Code Samples page, which shows how to make Gibraltar immediately send the package for the current session whenever an error is logged. Feeling a little sheepish, I admitted “Because I didn’t know we had that feature.”

It turns out, we have some pretty cool samples that do a lot of very useful things. If you haven’t had a chance to check them out yet, you should. This also got me thinking about some ways we can make our samples more visible and accessible. Stay tuned for some cool web site updates in the coming weeks.

Before I go, I wanted to suggest a slight tweak to the “Submitting Sessions on Error” sample I just pointed you to. In .NET 3.5 and later (4.0 for you VBers out there), you can take advantage of Lambda Expressions to simplify this call a little bit. The version I use looks like this:

protected void Application_Start()
{
    Log.MessageAlert += (sender, e) =>
                                {
                                    if (e.TopSeverity <= LogMessageSeverity.Error)
                                    {
                                        e.SendSession = true;
                                        e.MinimumDelay = new TimeSpan(0, 5, 0);
                                    }
                                };
}

Or for the VB folk:

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    AddHandler Log.MessageAlert, Sub(sender1 As Object, e1 As LogMessageAlertEventArgs)
                                 If (e1.TopSeverity <= LogMessageSeverity.Error) Then
                                     e1.SendSession = True
                                     e1.MinimumDelay = New TimeSpan(0, 5, 0)
                                 End If
                             End Sub
End Sub

This is simply some neat syntactical sugar that IMO makes your code a bit easier to read. Instead of having to follow the event handler to another method, you can see how the event is handled right there, without another method signature clogging up your code. Under the covers, the compiler will create the signature as an anonymous method, and sort everything out for you. Neat, huh?

I learn something new every day around here. Hope this little tidbit makes you more productive.

Comments (1)
Jun
14

Reworking the Gibraltar AddIn API

Posted by: | Comments (0)

There’s a classic saying in designing software that you should plan on throwing the first one away.  I’ve never been very comfortable with that because it can be easily abused by a team to justify half-baked thinking, inadequate requirements and design, and just general hope instead of solid engineering.

That said, it’s generally been my experience that no matter how good and diligent you are when designing an API you’ll inevitably find that you’ve missed the mark as soon as the first set of users start solving real problems with it.   So, you’ll want to leave room to redo and rethink your original approach before you’re married to it.  This is the major reason that we shipped Gibraltar 2.2.0 as a Beta back in early April with our first vision of a Gibraltar Add In API.

Feedback from inside & outside

To make sure we got solid evidence that the design was sound we worked hard to get some existing customers as well as outsiders to try solving their challenges with the API.  We also did our own internal Red Team approach:  we asked Jay (who isn’t doing any day-to-day development on Gibraltar, but has extensive commercial development experience) to scratch his favorite itch with the API as well.  We’re going to publish more about what he built soon, but without going into details something significant emerged from his work and discussions with our customers.

Instead of people using the API to solve a few tactical problems (like data export or an alternate view of the data) people wanted to use it to extensively integrate Gibraltar with external systems. This went way beyond our original intent; we have a big block of features on our roadmap for creating an external integration engine and hadn’t ever intended this to be the way that came about.  Despite that, it’s the problem people kept wanting to solve with the API.

Unfortunately, there are several things that we just didn’t allow for, but are common problems in these scenarios:

  • Configuration Management: Whenever you’re working between two systems, you’ll want some metadata to describe endpoints and map data between the systems.
  • Credential Management: Nobody likes hardcoding credentials, or doing something simple like popping them in a file without encryption.  We all know the right things to do, but it’s annoying and overhead.  It should be built in.
  • Coordination: All the various user interface and process extensions don’t exist in a vacuum; they need easy ways to coordinate their work to enable new processes, not just isolated features.
  • More Extensibility: People want to be able to extend other parts of the UI again with the goal of connecting processes together.
  • Development Debugging: In a twist of irony, it’s hard to log and view data from within an Add in because you’re running within the Gibraltar environment; you can’t use the Agent to log because you’re running inside of the Agent.  This made development of extensions a pain.

Powerful capabilities, not demoware

As we’ve said before, we hate demoware.   Although we’ve heard from a few parties that we just need to “check the feature box” with the API (have it but no one will use it), we just aren’t willing to accept that measure for success.  Instead, we see another angle:  We’re going to leverage the add in API ourself to enable us to create targeted features that only apply to some part of our audience so we can create them faster and keep control over the product’s complexity.  In short, we’ll make sure that it’ll solve problems for you by having it solve problems for us.

Fortunately, we didn’t have to throw the first one away in a literal sense.  We did end up discarding virtually our entire implementation of it from the Gibraltar side, but the change to the API you see is fairly modest.

We’re still finalizing the details, and deciding whether we need to do another beta round of 2.2 or should go ahead and formally release 2.2 so that everyone can get the benefit of all of the improvements that have happened over the past several months beyond the API.  But, we can speak to a few great features:

Configuration Management

Configuration data can be shared between the Hub and all of its connected Analysts.  This makes it more practical for add ins that connect systems together but need everyone on the team to share metadata on how items in both systems relate.  Since add ins can run on both the Hub and in the Analyst we made it so you can change the Hub configuration for an add in remotely.  This means you don’t have to run to IT and get on the server to say add new mappings for new projects or do whatever other configuration your favorite add in requires.  The central data is automatically synchronized between the Hub and Analyst and is available even if the Hub isn’t (say because you’re running disconnected from the network)

For example, say you want to integrate with your defect tracking system.  It’ll have some form of heirarchy for managing things – probably with different areas for the current development release vs. the production releases, etc.  You need to be able to relate the data Gibraltar has (like product and application names as well as versions) to those areas so when it opens or updates an issue it shows up in the right place and in the right workflow.

Credential Management

In a perfect world, your Windows credentials would give you access to any external system your Add In needs to access, so no credentials need to be stored.  Unfortunately, most of the third party systems you’ll want to integrate with (particularly ones that aren’t designed for enterprises) just flat won’t integrate that way.  You need to be able to store a user id and password but do so in a way that doesn’t create an unreasonable security risk.

We’ve baked in credential management leveraging the data protection API in Windows (DPAPI) so that you can encrypt account names and passwords so they can be accessed only by the current user, computer, or the hub.  Here again you can manage it all from Analyst, so if you need to change the account the Hub is using to login into your defect tracking system or something you don’t have to go to the server to do it.

Development Debugging

We’re taking advantage of improvements in the Live Log Viewer control to offer a real-time view of what’s happening with Add Ins, both the Gibraltar side and the messages logged by each Add In.  We log a lot of information as Analyst runs, and we don’t want to bury you in all of that detail so it automatically filters down to just information needed to monitor and support Add Ins.

This is done using only capabilities that are exposed through our normal API, so you can do the same thing in your WinForms/WPF application as well.  You’ll notice we’ve updated the live viewer to include a number of capabilities formerly only available in Analyst, like source code lookup and exception / detail viewing.

More Extensibility

We’ve added a number of places you can extend Gibraltar to the original list:

  • Analyze Sessions on Hub: Any analysis engine you create can run in Analyst or Hub.  We always intended it, but it wasn’t ready for the beta.  This means you can have data flowing from Gibraltar to external systems without anyone being logged in or having to leave something running.
  • Global Commands: You can extend the main Analyst menu bar with your own menu items to create global commands end users can easily access.
  • Controllers: We’ve added some key controller interfaces so you can hold state in the right places (think MVC) and substantially improve the efficiency of integrating with remote systems that may be expensive to query.
  • And More: Frankly, we’re going to continue adding items as we head towards release based on our internal experimentation of what we can safely get done and commit to.  Our ultimate goal is that you can extend each of the different views in Analyst so you can have it seamlessly participate in end-user workflow.

Real World Experience

We’ve been internally using the new API to help us automate our CEIP process for Gibraltar itself and it’s given us a lot of confidence not just in the new implementation but also in the vision it represents.  We’re going to be able to ship extensions outside of our release cycle, add optional modules in the box for a great initial experience, and help create a space for you to show your peers the cool things you can do where Gibraltar + Your System  = Awesome.

Is there a specific system you’d like to see us integrate with?  Drop us a line; we love to engage with our peers to understand new & creative ways to make a difference in how developers create rock solid .NET software.

Categories : .NET, Development, Logging
Comments (0)

We had a customer quiz us about why one of our thread names was showing up on some of their log messages.  We looked into the problem and were a bit baffled.  We name all of the threads we create inside the Agent to ensure we can separate what they do from any client application.  The name in question is used by a thread that the Gibraltar Agent creates and then destroys relatively early in the process.  This thread isn’t taken from the threadpool or put back into one, we confirmed it gets created and released so there just seemed no way that they could be processing on our thread.

We checked the data up and down and were confident that it wasn’t a data corruption problem – the only assumption made by the code was that Managed Thread Ids are unique.  This seemed pretty reasonable: the documentation for the ManagedThreadId property reads:

Thread.ManagedThreadId: Gets a unique identifier for the current managed thread.

But, we kept digging and found another scenario on a long running ASP.NET application where a similar event occurred – a thread that was created and destroyed relatively early in the application was clearly now in the thread pool and handling events.  Researching more, we found this gem in the documentation.  Not on the MSDN documentation for ManagedThreadId but rather for Thread.GetHashCode:

The hash code is not guaranteed to be unique. Use the ManagedThreadId property if you need a unique identifier for a managed thread.

OK, still pointing us that ManagedThreadId is the right guy for our use.  But then there’s this note on the Thread Class itself:

GetHashCode provides identification for managed threads. For the lifetime of your thread, it will not collide with the value from any other thread, regardless of the application domain from which you obtain the value.

This started to cast some concern:  That little bit of weasel room in the second sentence is troubling: “For the lifetime of your thread”…  Was .NET reusing thread Id’s after a thread exits?  The wiggle room in the statement above made that sound possible, even though there’s no reason necessarily that the hash code and the thread Id are related.  My first read of this was that the variation was about the second part of the sentence – uniqueness across application domains (which we never assumed).

So we created a few brutal tests – creating and destroying threads then ramping up the thread pool’s activity.  Sure enough, the same Managed Thread Ids showed up in the thread pool.  These weren’t the same threads – the thread static variables we were using for tests had been reset – but they had the same Managed Thread Id.

Go Team

The fix for us is to not rely on Managed Thread Id for correlating events to threads.  Instead, we’re using an internal thread static variable to track the relationship and identify it with our own unique identifier.  Because we track the thread responsible for log messages and many other things we record we had to represent this in the smallest amount of data feasible, and remain backwards/forwards compatible with existing data.

We’ve updated the display to automatically generate unique display names to separate out threads with the same Id’s and had to do a range of other adjustments to ensure we treat the Managed Thread Id as nothing more unique than a display name.   That way you’ll be sure that if two events are ascribed to something called “Thread 14″, they really are the same thread.  All of  the changes for this are included in Gibraltar 2.1.1 which will ship within the next few days (this was the last issue we needed to resolve before shipping).

Incomplete is worse than Missing

The frustrating part is that if the documentation had never made any claim about the uniqueness of the thread Id we’d likely have gone through a set of proof and qualification testing.  Like many people, when there isn’t documentation on something we have to create experiments to tease out the true behavior, review source code, and then decide what risks we want to take.  This is one reason we are passionate about documentation, even at the expense of extra features.  We want to make sure that you never have a doubt about what something on our API does.  We also know that people don’t want to review documentation if they don’t have to – so we try hard to make the API understandable just from Intellisense.

Now, I don’t want to knock Microsoft too hard here – .NET is a massive framework even if you just look at the core .NET 2.0 API.  But, as we all rely more and more on ever increasing layers of abstraction over what’s really going on it’s more important than ever to be precise in the documentation – about what something is and what it isn’t.  Precise is more important than being comprehensive, because it will set the right expectation for people about what they can rely on and what they’ll have to verify for themselves.

Categories : .NET, Development, Logging
Comments (5)