Are all of the methods of TCodeSiteLogger thread safe? In particular I'm wondering about SendFmtMsg, since the default usage of Format is not thread safe. Does SendFmtMsg use the thread safe version of Format?

Yes, the logger methods are thread safe. However, the SendFmtMsg in particular does use the default Format method call without the FormatSettings parameter. The warning in the help about the first version not being thread safe is a bit foreboding. The potential does exist that a global variable containing one of the format setting could be changed while it is being used in a Format call. The result would be that the formatted string may or may not have the newly changed format setting applied to the string. But the format will not fail or cause a problem with the SendFmtMsg call.

In a future update, we will probably modify the loggers to use a default TFormatSettings call, but there are issues with that as well. That is, ideally we would get the current defaults at startup and populate a private instance of TFormatSettings that would be used by all methods. However, the problem with this is that if the user does make system formatting changes, then the logger would not become aware of them. An alternative would be to get the local settings before each Format call. But this adds extra code to each method call, and not only that getting the local settings from a secondary thread may also produce inconsistent results.

A third alternative would be to provide an override for the user to provide a TFormatSettings value to use the call. Certainly doable and avoids the issues above. However, in this case, the regular SendMsg method could be used instead and the Format function called directly with a TFormatSettings parameter.

Raize Support wrote:The warning in the help about the first version not being thread safe is a bit foreboding. The potential does exist that a global variable containing one of the format setting could be changed while it is being used in a Format call. The result would be that the formatted string may or may not have the newly changed format setting applied to the string. But the format will not fail or cause a problem

I thought this as well. However, there is enough chatter on various forums about Format's thread safeness that I thought there may be something I was missing.

...

Raize Support wrote:However, in this case, the regular SendMsg method could be used instead and the Format function called directly with a TFormatSettings parameter.

I expect the category of "User logged in" would be 'Maintenance'. If that is the case, I'll probably create a separate TCodeSiteLogger object for each thread. Our application can have upwards of 200 threads at any given time. Any concerns with having that many different logger objects?

The properties are tied to the logger and are copies are not maintained for additional threads. If you want to categorize a different set of messages, it is best to use a separate TCodeSiteLogger instance.

In your example, if the CodeSite.Send( 'User logged in' ) message was sent after Thread 2 sets the CodeSite.Category, then yes, the category of the message would be 'Maintenance'.

In regards to the number of threads, there shouldn't be any issues. However, I would suggest asking why you need a separate logger for each thread. Is it just to assign a category to the CS messages from each thread? Do you need the color coding of the category? Do you need to need to be able to identify which thread a CS message was generated in? In this last case, note that each CodeSite message records which thread it was generated in. And with the Organize Message functionality and filtering in the viewers, you can quickly isolate the messages from a given thread.

Raize Support wrote:why you need a separate logger for each thread. Is it just to assign a category to the CS messages from each thread?

Yes. I'm still thinking through the strategy for implementing CodeSite logging in our application server. But here is my current idea:

Our DataSnap application server has 16 separate server modules (remote data modules). Logging will occur from each of these server modules. Each user's session is a separate thread, so all server modules accessed by a given user will have the same thread ID.

So it would be nice to:

Organize the activity by user - already possible using Thread ID.

Organize the activity by server module. Possible if the category is set based on the server module. Even in this case, the entry of any server method that calls CodeSite would need to set Category, as a single user would generate logging from multiple server modules. An extreme alternative would be to create a separate logger for each server module created. However, I think the overhead of setting the category each time is far less than the overhead of up to 16x the number of logging objects.

Isolate the activity to one specific user's activity in one specific server module. Possible using both Thread ID and Category.

View all activity sequentially, when researching issues where different threads may cause problems with other threads, such as synchronization, blocking, and related performance issues.

I already have EnterMethod/ExitMethod calls for each server method. Adding a line to set the category before the EnterMethod would be easy enough.

Our previous logging had a "on / off" switch, so we could turn the logging on as needed. My understanding is that CodeSite has practically zero overhead when CodeSiteManager.Enabled = False.

I'm a little confused by the Organize the activity by server module item. If you create a logger for each server module (16 of them) and set the Category for each server module logger when you create them, why would you need to set the Category again at the entry of each server method? The category would identify the server module and the thread would identify the user. But with all that said, your last sentence suggests that new instances of the server modules are created for each user (up to 16x). Is that correct?

And yes, setting CodeSiteManager.Enabled to False will turn off all logging and have practically zero overhead. You can also disable individual loggers by setting the logger's Enabled property to False.

Raize Support wrote:If you create a logger for each server module (16 of them) and set the Category for each server module logger when you create them, why would you need to set the Category again at the entry of each server method?

But with all that said, your last sentence suggests that new instances of the server modules are created for each user (up to 16x). Is that correct?

Up to 16 server modules per user, correct. Since each user has a separate server module instance, that could lead to a couple of thousand logging objects allocated. In that scenario, I could just set the Category once. But I expect the overhead of setting the category before calling EnterMethod is less than the overhead of having a separate logging object instantiated for every server module instantiated.

Brief overview of current architecture:

16 Server Modules

Each user has a dedicate thread

Each user will access a minimum of 3 server modules, up to 16 if the user hits every area of the application

Currently, a server module lives until the user that created it logs out

The next version will implement an object pool for the server modules. Some tuning will be done to find the optimal use of the object pool. I expect CodeSite will be very instrumental in that tuning process.

Our largest customer has 160 simultaneous users. So here are the options that I'm weighing:

Use only the built-in CodeSite logging object.

One logging object per user/thread (up to 160, until we get a larger customer)

One logging object per server module instance (up to 2,560)

The third option isn't even a consideration for me. I see zero benefit. I also expect that configuration would be more likely to become unstable.

So I'm trying to decide whether to use a single CodeSite logging object or one per thread. In either scenario, the logging object can/will be used to log from any server module instance at any given time. I was thinking that one object per user/thread would have some advantages.

The decision would be easier with knowledge of the CodeSite logging class, in particular how much (if any) serialization has to be done for thread safeness. Since the application server already has one thread per user anyway, creating one logging object per thread doesn't create much overhead. If there would be any performance benefit at all, it would be worth it.