Correlating IComMethodEvents

c#, c++, com+, delphi, monitoring

Solution

...if the events for some reason are fired out of order...

They never do. The COM+ system event publisher fires these events using COM+ Events service. Invocation of an event is synchronous from event publisher's point of view. When a publisher fires an event, it doesn't proceed with the next one until all the subscribers complete processing of fired event. Quite naturally, `OnMethodReturn/OnMethodException` events are not published before matching `OnMethodCall` ones. I recall reading KBs concerning race conditions/broken subscriptions in COM+ events. All of those bugs, to my knowledge, have been addressed in various Service Packs for Windows 2000. Though, admittedly, I do not try to stay up-to-date in this area.

When implementing `IComMethod2Events` you subscribe to the very same transient subscription as for `IComMethodEvents`. So order of fired events is the same too.

...so correlation has to be done using at least `oid` and `original caller`...

At this point I'm really not sure whether you do interpret results of your tests correctly. How do you test, exactly?

`oid` should already encapsulate all the information required, even in "multiple clients" scenario with JIT and pooling. Last time I implemented such event listener (it has been a while), relying on `oid` worked out fine. Though, majority of components in my environment was written in VB6 (hence, lived in STA). Yet, even with STA you can have several calls at various stages of execution by a single thread. As there is an upper bound for number of threads in COM+ STA thread pool you can have the following situation: call A starts on particular thread, call B starts on the same thread, call B returns, call A returns. I do not recall any trouble tracking the calls by `oid` without "some additional info about the caller".

Implementation idea you consider is, by large, canonical. `COM+ spy` sample that comes with Platform SDKs uses `oid` argument to trace individual calls. You can find the application's sources in `<Path to SDK samples>\Samples\com\administration\spy`. The sample has been using this implementation for quite a while (since Windows 2003 at least). And today it is aeons after MTA and even COM+ introduction. Should there be flaws the sample would be updated at this point. Hopefully.

Problem

When implementing IComMethodEvents you get three events. - OnMethodCall - OnMethodException - OnMethodReturn The goal of what I am trying to do is to log call times per method in COM+ components. The time of the event can be retrieved by using `lTime` and `lMicroTime` in the COMSVCSEVENTINFO structure so by logging that time in both `OnMethodCall` and in `OnMethodReturn` I should be able to calculate the call time but how can I be sure that the two events are related. By testing it looks as I should be able to use the just-in-time (JIT) activated object `oid`. Any problems in doing it like that or are there other ways? One problem that might be is that I see the `oid` is frequently being reused so if the events for some reason is fired out of order it might be a bit more difficult to implement the correlation. Update 1: Further testing shows that `oid` is not enough in a multi user scenario. The same object is used at the same time so correlation has to be done using at least `oid` and `original caller`. A follow up question would be: How to get the original caller from a COM+ event subscriber? Update 2: Just found IComMethod2Events. Difference is that the events has an identifier of the thread executing the call. Looks promising in tests and I can't imagine a scenario where the correlation could fail. The threading model for the COM+ components are `Any Apartment`. Update 3 In this article Creating COM+ PerfMon Counters to Monitor COM+ Data `oid` is used. I don't think that is enough in a multithreaded apartment. Note: I will eventually implement this in Delphi so I added the Delphi tag. I also added the C# tag because chances are that the language used to implement the interface is not important at all. Update: Tentatively adding the c++ tag just to draw the attention of someone who has actually used this stuff before.

Original source