Mini-SOD for unifying producer and client logging
"Eric Hyche" <[email protected]>
| Newsgroups | gmane.comp.multimedia.helix.devel |
|---|---|
| Organization | RealNetworks, Inc. |
| Message-ID | <006501c99b52$b83144f0$2893ced0$@com> |
All: Please find attached a mini-SOD for the necessary changes for: a) getting logging working on Producer builds; and b) allowing Helix client plugins log messages simultaneously with producer sdk log messages. I have already discussed these changes with Sujeet and Milko. Sujeet: this is only a slight modification from what we discussed last week. I started on these changes last week and should be finished by EOD Tuesday. If you have any questions, comments, or feedback, please let me know. Eric ======================================= Eric Hyche ([email protected]) Principal Engineer RealNetworks, Inc. _______________________________________________ Helix-client-dev mailing list [email protected] http://lists.helixcommunity.org/mailman/listinfo/helix-client-dev
LoggingMiniSOD.txt
(text/plain, 9.5 KB)
Statement of Design for Unifying Producer and Client Logging
-------------------------------------------------------------------
The Producer SDK logging system was adopted by the Helix client
several years ago. At the time, we kept several things about
the implementation separate - different macros, different ways of
initializing, different way of loading the logging system DLL, etc.
We kept this separation because so that both systems could continue
to operate with no changes.
Now that the Producer SDK is integrated with the Helix client Atlas
platform, we need to unify how both systems use logging.
Here is an overview of the current way that the Helix
client uses logging (before the changes I'm proposing in this
document).
- Logging observer plugins implement IHXPlugin and IHXPluginProperties
and in IHXPluginProperties::GetProperties(), they advertise a
property named "LoadAtStartup" which has a value of "MediaPlatform".
- When the media platform is initialized via IHXMediaPlatform::Init(),
is queries the plugin handler for all plugins with a property
named "LoadAtStartup" equal to "MediaPlatform". It then takes
the plugin enumerator returned by the plugin handler and loads
each of these plugins and calls IHXPlugin::InitPlugin() on them.
- Right now there is only one observer plugin - the observer which
writes log statements to a file in common/log/logobserverfile.
When this plugin gets a call to IHXPlugin::InitPlugin(), it
reads the following preferences rooted at "Logging/File"
in the preference tree:
"Enabled" - enable/disable this observer
"DeliveryThread" - use a separate thread for delivery of log messages
to the observers
"Filename" - filename of the log file
"LevelFilter" - only display logging messages of this level
"AreaFilter" - comma-separated list of logging 4cc's (listed
in common/include/ihxtlogsystem.h)
"Separator" - character used to separate fields in log statements
These values have defaults if there is no preference present.
- Using these values, the appropriate calls to IHXTFileObserver are
made like IHXTFileObsever::Enable(), IHXTFileObserver::SetCategoryFilter(),
IHXTFileObserver::SetSeparator(), and finally IHXTFileObserver::Init()
is called, passing in the filename of the log file.
- Inside IHXTFileObserver::Init(), the file observer uses DLLAccess to
load the logging system dll (log.dll in common/log/logsystem). It then
calls It then calls the "RMACreateLogSystem" entrypoint to get a pointer
to the IHXTLogSystem interface. From the IHXTLogSystem pointer, it
calls IHXTLogSystem::GetObserverManagerInterface() to get the observer
manager than then uses the observer manager to subscribe the file
observer into the log system.
- In code that wants to make logging statements, somewhere in the binary
there must be a call to HX_ENABLE_LOGGING(pContext). The code in hxtlogutil
library (common/log/logutil) will take that context, QI it for IHXCommonClassFactory,
and then call CreateInstance(CLSID_IHXDllAccess,), and then use that
IHXDllAccess object to load the logging dll (log.dll) and calls the
"RMACreateLogSystem" entrypoint to get an IHXTLogSystem pointer. It then
calls IHXTLogSystem::GetWriterInterface() to get the writer interface
which it sets into a global static variable.
- So the Helix client's usage of the logging system is "automatic". As long
as logging statements are present, then if log.dll and logobserver.dll
are present in the plugins directory, then the logging file appears.
The Producer SDK takes a much more "manual" approach to using logging.
- The application manually loads the logging system dll (log.dll), gets
the "RMACreateLogSystem" entrypoint which creates a singleton global
variable IHXTLogSystem pointer inside the log.dll binary (this is the
same as in the client). It also then manually loads the file observer
by calling CreateInstance(CLSID_IHXTFileObserver,) on its factory.
- From the UI or command line parameters, it sets the values on
IHXTFileObserver and then calls IHXTFileObserver::Init() which subscribes
the file observer to the log system same as in the client. However,
it calls the "RMAGetLogSystem" entrypoint which returns a IHXTLogSystem
pointer ONLY if one has already been created. In other words, it assumes
that the log system has already been created by the application.
- Code that wants to write logging statements use different macros
to write log statements, although these macros eventually map to the
same underlying function call of IHXTLogWriter::LogMessage().
- Also, in code that wants to write logging statements, the Producer SDK
plugins do not require a context or an HX_ENABLE_LOGGING macro.
That's because they maintain a global static DLLAccess class which
is used to load the logging dll.
Previously we used the presence of the HELIX_FEATURE_LOG_STATICDLLACCESS
to distinguish between these two ways of using the log system.
The HELIX_FEATURE_LOG_STATICDLLACCESS define was present in helix-producer-all-defines
but not present in helix-client-all-defines. However, now we are
building with the same profile, so we would like to be able to
have both Helix client logging messages and Producer SDK logging
messages in the same log file.
Therefore, I propose we unify these two approaches such that both can
continue to operate as they desire but we don't have this compile-time
decision of whether to support either Helix client logging
or Producer SDK logging. Here are the changes I propose:
1) Make the logging DLL an IHXComponentPlugin for Atlas. That means that
the media platform can create an instance of IHXTLogSystem simply
by calling its CreateInstance() method. The previous "RMACreateLogSystem"
and "RMAGetLogSystem" will still be exposed, but they will return
HXR_NOTIMPL and will throw an HX_ASSERT() if called.
2) Change the log observers (currently only the file observer)
IHXPluginProperties to advertise a "PluginType" of "LogObserver"
instead of "LoadAtStartup" = "MediaPlatform".
3) We define a new interface called IHXLogSystemManager. The methods
of IHXLogSystemManager are:
InitializeLogSystem() - this loads the log system by calling
CreateInstance(CLSID_IHXTLogSystem,) on the media platform
IHXCommonClassFactory.
TerminateLogSystem() - this calls IHXTLogSystem::Shutdown()
and then releases the log system.
GetLogSystem(REF(IHXTLogSystem*) rpLogSystem) - this returns the log system
InitializeLogObservers() - Load, configure, and subscribe
all log observers
TerminateLogObservers() - Unsubscribe and unload the log observers
4) We add another "basic service" to the Atlas platform - log
system management. What this means is:
a) In IHXMediaPlatform::Init(), the media platform checks
to see if the context that the application passed in
(if present) supports IHXLogSystemManager.
- If it does, then it uses that IHXLogSystemManager
interface and holds a reference to it in the media platform.
- If it does not (or the context is NULL), then the media
platform creates its own internal implementation
of IHXLogSystemManager.
In either case, the media platform can now be QI'd for
IHXLogSystemManager.
b) In IHXMediaPlatform::Init() after we obtain an IHXLogSystemManager
(either from the Init() context or by creating our own internal
instance), then the media platform calls
IHXLogSystemManager::InitializeLogSystem() and then
IHXLogSystemManager::InitializeLogObservers().
c) In IHXMediaPlatform::Close(), the media platform calls
IHXLogSystemManager::TerminateLogObservers() and then
IHXLogSystemManager::TerminateLogSystem().
5) The Helix client will have a default implementation of
IHXLogSystemManager located in common/log/logutil. The default
implementation will do what the client does now - configure the
file observer from preferences.
6) Producer applications will need to be modified to implement
IHXLogSystemManager. The Producer could re-use some parts
of the client's IHXLogSystemManager implementation. However,
it's implementation would set the file observer properties
from user input instead of reading from preference. Also, the
command-line producer would create and initialize the
"screen logger" as it currently does.
7) common/log/logutil/hxtlogutil.cpp would be changed so that
when we call HXEnableLogging(pContext), we just QI pContext
for IHXLogSystemManager and then call
IHXLogSystemManager::GetLogSystem() to get an IHXTLogSystem
pointer. Everything else (getting the IHXTLogWriter and
IHXTLogSystemContext interfaces from IHXTLogSystem) would
stay the same.
8) We will update the logmessages.xml file:
a) to use 4cc's for the "id" attribute in <FunctionalArea>
elements instead of ordinal numbers;
b) to add <FunctionalArea> elements for the client logging 4cc's
9) Update LoadTranslationFile() method in
common/log/logsystem/hxttranslationcentre.cpp to parse the
new "id" attribute (which are now 4cc's).
Tasks:
1) Make log.dll into an Atlas component plugin (3 hours, DONE)
2) Change logobserver plugin properties (0.1 hour)
3) Change media platform to use IHXLogSystemManager (1 hour)
4) Provide default implementation of IHXLogSystemManager (2 hours)
5) Modify command-line producer to implement IHXLogSystemManager (2 hours)
6) Update logmessages.xml file (1 hour)
7) Update LoadTranslationFile() to handle new "id" attribute (1 hour)