Skip to content

Commit 8996d9b

Browse files
authored
Add diagnostics to dynamic factory (#4757)
## Change Adds diagnostics to the dynamic factory.
1 parent 43686bb commit 8996d9b

File tree

1 file changed

+100
-38
lines changed

1 file changed

+100
-38
lines changed

src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp

Lines changed: 100 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,49 @@ namespace AppInstaller::CLI::ConfigurationRemoting
3636
}
3737
#endif
3838

39+
// This is implemented completely in the packaged context for now, if we want to make it more configurable, we will probably want to move it to configuration and
40+
// have this implementation leverage that one with an event handler for the packaged specifics.
41+
// TODO: Add SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties and pass values along to sets on creation
42+
// In turn, any properties must only be set via the command line (or eventual UI requests to the user).
43+
struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
44+
{
45+
DynamicFactory();
46+
47+
IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet);
48+
49+
winrt::event_token Diagnostics(const EventHandler<IDiagnosticInformation>& handler);
50+
void Diagnostics(const winrt::event_token& token) noexcept;
51+
52+
DiagnosticLevel MinimumLevel();
53+
void MinimumLevel(DiagnosticLevel value);
54+
55+
HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher);
56+
57+
IConfigurationSetProcessorFactory& DefaultFactory();
58+
59+
void SendDiagnostics(const IDiagnosticInformation& information);
60+
61+
private:
62+
IConfigurationSetProcessorFactory m_defaultRemoteFactory;
63+
winrt::event<EventHandler<IDiagnosticInformation>> m_diagnostics;
64+
IConfigurationSetProcessorFactory::Diagnostics_revoker m_factoryDiagnosticsEventRevoker;
65+
std::mutex m_diagnosticsMutex;
66+
DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational;
67+
};
68+
3969
struct DynamicProcessorInfo
4070
{
4171
IConfigurationSetProcessorFactory Factory;
4272
IConfigurationSetProcessor Processor;
73+
IConfigurationSetProcessorFactory::Diagnostics_revoker DiagnosticsEventRevoker;
4374
};
4475

4576
struct DynamicSetProcessor : winrt::implements<DynamicSetProcessor, IConfigurationSetProcessor>
4677
{
4778
using ProcessorMap = std::map<Security::IntegrityLevel, DynamicProcessorInfo>;
4879

49-
DynamicSetProcessor(IConfigurationSetProcessorFactory defaultRemoteFactory, IConfigurationSetProcessor defaultRemoteSetProcessor, const ConfigurationSet& configurationSet) : m_configurationSet(configurationSet)
80+
DynamicSetProcessor(winrt::com_ptr<DynamicFactory> dynamicFactory, IConfigurationSetProcessor defaultRemoteSetProcessor, const ConfigurationSet& configurationSet) :
81+
m_dynamicFactory(std::move(dynamicFactory)), m_configurationSet(configurationSet)
5082
{
5183
#ifndef AICLI_DISABLE_TEST_HOOKS
5284
m_enableTestMode = GetConfigurationSetMetadataOverride(m_configurationSet, EnableTestModeTestGuid);
@@ -58,7 +90,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
5890
m_currentIntegrityLevel = Security::GetEffectiveIntegrityLevel();
5991
#endif
6092

61-
m_setProcessors.emplace(m_currentIntegrityLevel, DynamicProcessorInfo{ defaultRemoteFactory, defaultRemoteSetProcessor });
93+
m_setProcessors.emplace(m_currentIntegrityLevel, DynamicProcessorInfo{ m_dynamicFactory->DefaultFactory(), defaultRemoteSetProcessor});
6294
}
6395

6496
IConfigurationUnitProcessorDetails GetUnitProcessorDetails(const ConfigurationUnit& unit, ConfigurationUnitDetailFlags detailFlags)
@@ -212,6 +244,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
212244
ProcessorMap::iterator CreateSetProcessorForIntegrityLevel(Security::IntegrityLevel integrityLevel)
213245
{
214246
IConfigurationSetProcessorFactory factory;
247+
IConfigurationSetProcessorFactory::Diagnostics_revoker factoryDiagnosticsEventRevoker;
215248

216249
// If we got here, the only option is that the current integrity level is not High.
217250
if (integrityLevel == Security::IntegrityLevel::High)
@@ -228,9 +261,22 @@ namespace AppInstaller::CLI::ConfigurationRemoting
228261
THROW_WIN32(ERROR_NOT_SUPPORTED);
229262
}
230263

231-
return m_setProcessors.emplace(integrityLevel, DynamicProcessorInfo{ factory, factory.CreateSetProcessor(m_configurationSet) }).first;
264+
if (factory)
265+
{
266+
factoryDiagnosticsEventRevoker = factory.Diagnostics(winrt::auto_revoke,
267+
[weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
268+
{
269+
if (auto strong_this{ weak_this.get() })
270+
{
271+
strong_this->m_dynamicFactory->SendDiagnostics(information);
272+
}
273+
});
274+
}
275+
276+
return m_setProcessors.emplace(integrityLevel, DynamicProcessorInfo{ factory, factory.CreateSetProcessor(m_configurationSet), std::move(factoryDiagnosticsEventRevoker) }).first;
232277
}
233278

279+
winrt::com_ptr<DynamicFactory> m_dynamicFactory;
234280
Security::IntegrityLevel m_currentIntegrityLevel;
235281
ProcessorMap m_setProcessors;
236282
ConfigurationSet m_configurationSet;
@@ -243,52 +289,68 @@ namespace AppInstaller::CLI::ConfigurationRemoting
243289
#endif
244290
};
245291

246-
// This is implemented completely in the packaged context for now, if we want to make it more configurable, we will probably want to move it to configuration and
247-
// have this implementation leverage that one with an event handler for the packaged specifics.
248-
// TODO: Add SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties and pass values along to sets on creation
249-
// In turn, any properties must only be set via the command line (or eventual UI requests to the user).
250-
struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
292+
DynamicFactory::DynamicFactory()
251293
{
252-
DynamicFactory()
253-
{
254-
m_defaultRemoteFactory = CreateOutOfProcessFactory();
255-
}
294+
m_defaultRemoteFactory = CreateOutOfProcessFactory();
256295

257-
IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet)
296+
if (m_defaultRemoteFactory)
258297
{
259-
return winrt::make<DynamicSetProcessor>(m_defaultRemoteFactory, m_defaultRemoteFactory.CreateSetProcessor(configurationSet), configurationSet);
298+
m_factoryDiagnosticsEventRevoker = m_defaultRemoteFactory.Diagnostics(winrt::auto_revoke,
299+
[weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
300+
{
301+
if (auto strong_this{ weak_this.get() })
302+
{
303+
strong_this->SendDiagnostics(information);
304+
}
305+
});
260306
}
307+
}
261308

262-
winrt::event_token Diagnostics(const EventHandler<IDiagnosticInformation>&)
263-
{
264-
// TODO: If we want diagnostics here, see ConfigurationProcessor for how to integrate nicely with the infrastructure.
265-
// Best solution is probably to create a base class that both can leverage to handle it cleanly.
266-
return {};
267-
}
309+
IConfigurationSetProcessor DynamicFactory::CreateSetProcessor(const ConfigurationSet& configurationSet)
310+
{
311+
return winrt::make<DynamicSetProcessor>(get_strong(), m_defaultRemoteFactory.CreateSetProcessor(configurationSet), configurationSet);
312+
}
268313

269-
void Diagnostics(const winrt::event_token&) noexcept
270-
{
271-
}
314+
winrt::event_token DynamicFactory::Diagnostics(const EventHandler<IDiagnosticInformation>& handler)
315+
{
316+
return m_diagnostics.add(handler);
317+
}
272318

273-
DiagnosticLevel MinimumLevel()
274-
{
275-
return m_minimumLevel;
276-
}
319+
void DynamicFactory::Diagnostics(const winrt::event_token& token) noexcept
320+
{
321+
m_diagnostics.remove(token);
322+
}
277323

278-
void MinimumLevel(DiagnosticLevel value)
279-
{
280-
m_minimumLevel = value;
281-
}
324+
DiagnosticLevel DynamicFactory::MinimumLevel()
325+
{
326+
return m_minimumLevel;
327+
}
282328

283-
HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher)
329+
void DynamicFactory::MinimumLevel(DiagnosticLevel value)
330+
{
331+
m_minimumLevel = value;
332+
}
333+
334+
HRESULT STDMETHODCALLTYPE DynamicFactory::SetLifetimeWatcher(IUnknown* watcher)
335+
{
336+
return WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher);
337+
}
338+
339+
IConfigurationSetProcessorFactory& DynamicFactory::DefaultFactory()
340+
{
341+
return m_defaultRemoteFactory;
342+
}
343+
344+
void DynamicFactory::SendDiagnostics(const IDiagnosticInformation& information) try
345+
{
346+
if (information.Level() >= m_minimumLevel)
284347
{
285-
return WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher);
348+
std::lock_guard<std::mutex> lock{ m_diagnosticsMutex };
349+
m_diagnostics(*this, information);
286350
}
287-
288-
private:
289-
IConfigurationSetProcessorFactory m_defaultRemoteFactory;
290-
DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational;
291-
};
351+
}
352+
// While diagnostics can be important, a failure to send them should not cause additional issues.
353+
catch (...) {}
292354
}
293355

294356
winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateDynamicRuntimeFactory()

0 commit comments

Comments
 (0)