예제 #1
0
        private void TryCleanupContainerFolderScheduledForRemoval(ContainerFolderScheduledForRemoval containerScheduledForRemoval)
        {
            if (containerScheduledForRemoval.IsProcessingWaitTimeExpired(this.containerEnvironment.MaxContainerLogsProcessingWaitTime) &&
                this.TryRemovingContainerAppInstanceAndLogFolder(containerScheduledForRemoval))
            {
                ContainerFolderScheduledForRemoval unusedOutParameter;

                if (this.containersFoldersScheduledForRemoval.TryRemove(
                        containerScheduledForRemoval.ContainerLogFullPath,
                        out unusedOutParameter))
                {
                    Utility.TraceSource.WriteInfo(
                        TraceType,
                        "Successfully removed container traces folder: {0},  and AppInstance : {1}",
                        containerScheduledForRemoval.ContainerLogFullPath,
                        ContainerEnvironment.GetAppInstanceIdFromContainerFolderFullPath(containerScheduledForRemoval.ContainerLogFullPath));
                }
                else
                {
                    Utility.TraceSource.WriteInfo(
                        TraceType,
                        "Failed to removed container traces folder from ContainerFolderScheduledForRemoval list. Container folder path : {0}",
                        containerScheduledForRemoval.ContainerLogFullPath);
                }
            }
        }
예제 #2
0
        private void InitializeProcessingOfContainerLogsFolder(string containerLogFolderFullPath)
        {
            string appInstanceId = ContainerEnvironment.GetAppInstanceIdFromContainerFolderFullPath(containerLogFolderFullPath);

            lock (this.appInstanceManagerLock)
            {
                // this is needed because of the race condition we have at startup
                // where watcher could be triggered before initial folders are listed and processed.
                if (!this.appInstanceManager.Contains(appInstanceId))
                {
                    this.appInstanceManager.CreateApplicationInstance(appInstanceId, null);
                }
            }
        }
예제 #3
0
        private bool TryRemovingContainerAppInstanceAndLogFolder(ContainerFolderScheduledForRemoval deletedContainer)
        {
            try
            {
                lock (this.appInstanceManagerLock)
                {
                    this.appInstanceManager.DeleteApplicationInstance(ContainerEnvironment.GetAppInstanceIdFromContainerFolderFullPath(deletedContainer.ContainerLogFullPath));
                }
            }
            catch (Exception e)
            {
                Utility.TraceSource.WriteInfo(TraceType, "Failed to remove appInstance with exception: {0}", e);
            }

            return(this.TryRemoveContainerFolder(deletedContainer.ContainerLogFullPath));
        }
예제 #4
0
        internal ContainerManager(AppInstanceManager appInstanceManager, ContainerEnvironment containerEnvironment)
        {
            this.appInstanceManager   = appInstanceManager;
            this.containerEnvironment = containerEnvironment;

            Utility.TraceSource.WriteInfo(
                TraceType,
                "Watching directory for creation of new container trace folders {0}",
                this.containerEnvironment.ContainerLogRootDirectory);

            // Watcher needs to be created before startup listing of folders
            // Otherwise there is the risk a file will be created between the two and it will be missed.
            // WriteLock is created so prevent race condition with file watchers
            this.processingMarkersRWLock.EnterWriteLock();
            try
            {
                if (Directory.Exists(this.containerEnvironment.ContainerLogRootDirectory))
                {
                    this.CreateContainerFolderWacher();

                    foreach (var directory in Directory.EnumerateDirectories(this.containerEnvironment.ContainerLogRootDirectory))
                    {
                        this.ContainerLogFolderProcessingStartup(directory);
                    }
                }
                else
                {
                    Utility.TraceSource.WriteError(
                        TraceType,
                        "Not monitoring directory for creation of new container trace folders since directory doesn't exist {0}",
                        this.containerEnvironment.ContainerLogRootDirectory);
                }
            }
            finally
            {
                this.processingMarkersRWLock.ExitWriteLock();
            }

            // Arm the cleanup timer.
            this.cleanupTimer = new DcaTimer(
                ContainerManager.TraceType,
                new TimerCallback(this.BackgroundCleanup),
                (long)this.containerEnvironment.ContainerFolderCleanupTimerInterval.TotalMilliseconds);
            this.cleanupTimer.Start((long)this.containerEnvironment.ContainerFolderCleanupTimerInterval.TotalMilliseconds);
        }
예제 #5
0
        private void ContainerLogFolderProcessingStartup(string containerLogFolderFullPath)
        {
            string appInstanceId = ContainerEnvironment.GetAppInstanceIdFromContainerFolderFullPath(containerLogFolderFullPath);

            Utility.TraceSource.WriteInfo(TraceType, "Initializing handling of container traces from {0}", appInstanceId);

            bool containsProcessLogMarker = File.Exists(Path.Combine(containerLogFolderFullPath, ContainerEnvironment.ContainerProcessLogMarkerFileName));

            if (containsProcessLogMarker)
            {
                this.InitializeProcessingOfContainerLogsFolder(containerLogFolderFullPath);
            }

            bool containsRemoveLogMarker = File.Exists(Path.Combine(containerLogFolderFullPath, ContainerEnvironment.ContainerRemoveLogMarkerFileName));

            if (containsRemoveLogMarker)
            {
                this.ScheduleRemovalOfContainerAppInstanceAndFolder(containerLogFolderFullPath);
            }
        }
        public void BackgroundCleanup(object context)
        {
            foreach (var applicationInstanceId in this.applicationInstancesToDelete)
            {
                Utility.TraceSource.WriteInfo(TraceType, "Container traces folder being deleted {0}", applicationInstanceId);
                var fullPath = ContainerEnvironment.GetContainerLogFolder(applicationInstanceId);
                var files    = Directory.GetFiles(fullPath);
                if (files.Length == 1 && Path.GetFileName(files[0]) == ContainerEnvironment.ContainerDeletionMarkerFileName)
                {
                    try
                    {
                        this.appInstanceManager.DeleteApplicationInstance(applicationInstanceId);
                        Directory.Delete(fullPath, true);
                    }
                    catch (Exception e)
                    {
                        Utility.TraceSource.WriteInfo(TraceType, "Container traces folder delete failed {0} becauuse {1}. Will retry later", applicationInstanceId, e);
                    }
                }
            }

            this.cleanupTimer.Start();
        }
예제 #7
0
        /// <summary>
        /// Create destination file name for filtered trace.
        /// </summary>
        /// <param name="etlFileName"></param>
        /// <param name="isActiveEtl"></param>
        /// <returns></returns>
        private string CreateDestinationFileName(string etlFileName, bool isActiveEtl)
        {
            string differentiator = string.Format(
                CultureInfo.InvariantCulture,
                "{0:D10}",
                isActiveEtl ? this.lastEventIndexProcessed.TimestampDifferentiator : int.MaxValue);

            string traceFileNamePrefix = string.Format(
                CultureInfo.InvariantCulture,
                "{0}_{1}_{2:D20}_{3}.",
                this.fabricNodeId,
                Path.GetFileNameWithoutExtension(etlFileName),
                this.lastEventIndexProcessed.Timestamp.Ticks,
                differentiator);

            var applicationInstanceId = ContainerEnvironment.GetContainerApplicationInstanceId(this.logSourceId);

            if (ContainerEnvironment.IsContainerApplication(applicationInstanceId))
            {
                // Note that the a hash of the applicationInstanceId is being used to reduce file name length in around 70 characters
                // This is done to workaround PathTooLong exception in FileUploaderBase.cs since we don't have an interop for FileSystemWatcher
                // and .NET 4.5 used does not support long paths yet.
                traceFileNamePrefix = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}_{1:X8}_{2}_{3:D20}_{4}.",
                    this.fabricNodeId,
                    Path.GetFileName(applicationInstanceId).GetHashCode(),
                    Path.GetFileNameWithoutExtension(etlFileName),
                    this.lastEventIndexProcessed.Timestamp.Ticks,
                    differentiator);
            }

            return(string.Concat(
                       traceFileNamePrefix,
                       EtlConsumerConstants.FilteredEtwTraceFileExtension));
        }
예제 #8
0
        private void CopyTraceFileForUpload(string fileName)
        {
            // Build the destination name for the filtered trace file
            //
            //         !!! WARNING !!!
            // The trace viewer tool parses the file names of the filtered trace files.
            // Changing the file name format might require a change to trace viewer as well.
            //         !!! WARNING !!!
            //
            // If the ETL file is an active ETL file, the trace file name is of the form:
            // <FabricNodeID>_<etlFileName>_<TimestampOfLastEventProcessed>_<TimestampDifferentiatorOfLastEventProcessed>.dtr
            //
            // If the ETL file is an inactive ETL file, the trace file name is of the form:
            // <FabricNodeID>_<etlFileName>_<TimestampOfLastEventProcessed>_<Int32.MaxValue>.dtr
            //
            // Using Int32.MaxValue as a component of the trace file name makes
            // it easy to identify gaps in the filtered traces if the DCA is
            // falling behind on trace processing. Recall that an inactive ETL
            // file is always processed fully. Only active ETL files are processed
            // in chunks. Therefore, the presence of Int32.MaxValue indicates that
            // the corresponding ETL file is inactive and has been fully processed
            // by the DCA. Thus, gaps **within** an ETL file (i.e. unprocessed
            // chunks within the file) can be identified by the absence of a file
            // containing Int32.MaxValue in its name.
            //
            // It is also worth noting that ETL file names are sequentially
            // numbered, which helps in identifying gaps **between** ETL files
            // (i.e. ETL files that were not processed at all). And the use of
            // Int32.MaxValue is an enhancement that enables us to identify gaps
            // within an ETL file. Using these two concepts, we can look at a set
            // of filtered trace files and determine whether they are complete.
            // And if not complete, we can also identify where all the gaps are.
            string differentiator = string.Format(
                CultureInfo.InvariantCulture,
                "{0:D10}",
                0);

            string newTraceFileName = "";
            long   lastEventTicks;

            try
            {
                if (logStartTime == 0)
                {
                    // We just need the start of log tracing file generation time stamp,
                    // for alligning with etw logs
                    //this.logStartTime = DateTime.Parse(Path.GetFileNameWithoutExtension(fileName).Replace("_", " ")).Ticks;
                    this.logStartTime = GetFirstEventTicks(fileName);
                }

                lastEventTicks = GetLastEventTicks(fileName);
            }
            catch (Exception e)
            {
                var fileNameDiscard = fileName + ".discard";

                this.traceSource.WriteExceptionAsWarning(
                    this.logSourceId,
                    e,
                    "Could not create filename for trace files for upload. Renaming file to {0}",
                    fileNameDiscard);

                // Rename the file and do not process it.
                try
                {
                    // Delete the file so that storage is not blocked
                    FabricFile.Delete(fileName);
                }
                catch (Exception ex)
                {
                    this.traceSource.WriteExceptionAsWarning(
                        this.logSourceId,
                        ex,
                        "Failed to rename file to {0}",
                        fileNameDiscard);
                }

                return;
            }

            // Create the filename which TraceViewer understands
            newTraceFileName = string.Format(
                CultureInfo.InvariantCulture,
                "fabric_traces_{0}_{1}_{2:D6}",
                fabricVersion,
                this.logStartTime,
                1);

            string traceFileNamePrefix = string.Format(
                CultureInfo.InvariantCulture,
                "{0}_{1}_{2:D20}_{3}.",
                this.fabricNodeId,
                newTraceFileName,
                lastEventTicks,
                differentiator);

            var applicationInstanceId = ContainerEnvironment.GetContainerApplicationInstanceId(this.logSourceId);

            if (ContainerEnvironment.IsContainerApplication(applicationInstanceId))
            {
                // Note that the a hash of the applicationInstanceId is being used to reduce file name length in around 70 characters
                // This is done to workaround PathTooLong exception in FileUploaderBase.cs since we don't have an interop for FileSystemWatcher
                // and .NET 4.5 used does not support long paths yet.
                traceFileNamePrefix = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}_{1:X8}_{2}_{3:D20}_{4}.",
                    this.fabricNodeId,
                    Path.GetFileName(applicationInstanceId).GetHashCode(),
                    newTraceFileName,
                    lastEventTicks,
                    differentiator);
            }

            string traceFileNameWithoutPath = string.Concat(
                traceFileNamePrefix,
                "dtr");

            string compressedTraceFileNameWithoutPath = string.Concat(
                traceFileNamePrefix,
                "dtr.zip");

            string subFolder = GetTraceFileSubFolder(fileName);

            string traceFileDestinationPath = Path.Combine(
                this.csvFolder,
                subFolder);

            string traceFileDestinationName = Path.Combine(
                traceFileDestinationPath,
                this.compressCsvFiles ?
                compressedTraceFileNameWithoutPath :
                traceFileNameWithoutPath);

            string alternateTraceFileDestinationName = Path.Combine(
                traceFileDestinationPath,
                this.compressCsvFiles ?
                traceFileNameWithoutPath :
                compressedTraceFileNameWithoutPath);

            try
            {
                InternalFileSink.CopyFile(fileName, traceFileDestinationName, false, this.compressCsvFiles);
                FabricFile.Delete(fileName);
                this.traceSource.WriteInfo(
                    this.logSourceId,
                    "Traces are ready. They have been moved from {0} to {1}.",
                    fileName,
                    traceFileDestinationName);
            }
            catch (Exception e)
            {
                this.traceSource.WriteExceptionAsError(
                    this.logSourceId,
                    e,
                    "Failed to move file from {0} to {1}.",
                    fileName,
                    traceFileDestinationName);
            }
        }
예제 #9
0
        private void CopyTraceFileForUpload(string fileName, bool isActiveEtl)
        {
            // If the temporary trace file does not contain events and if the ETL
            // file that is being processed is an active ETL file, then don't
            // copy the temporary file to the ETW CSV directory.
            //
            // In contrast, temporary trace files corresponding to inactive ETL
            // files are copied even if they don't have events in them (i.e. a
            // zero-byte file is copied) because it makes it easier to identify
            // gaps in traces if the DCA happens to fall behind on trace processing.
            // For details, please see comments later in this function.
            if (0 == this.fileSink.WriteStatistics.EventsWritten && isActiveEtl)
            {
                return;
            }

            // Build the destination name for the filtered trace file
            //
            //         !!! WARNING !!!
            // The trace viewer tool parses the file names of the filtered trace files.
            // Changing the file name format might require a change to trace viewer as well.
            //         !!! WARNING !!!
            //
            // If the ETL file is an active ETL file, the trace file name is of the form:
            // <FabricNodeID>_<etlFileName>_<TimestampOfLastEventProcessed>_<TimestampDifferentiatorOfLastEventProcessed>.dtr
            // For containers the file structure is:
            // <FabricNodeID>_<ContainerName>_<etlFileName>_<TimestampOfLastEventProcessed>_<TimestampDifferentiatorOfLastEventProcessed>.dtr
            //
            // If the ETL file is an inactive ETL file, the trace file name is of the form:
            // <FabricNodeID>_<etlFileName>_<TimestampOfLastEventProcessed>_<Int32.MaxValue>.dtr
            // For containers the file structure is:
            // <FabricNodeID>_<ContainerName>_<etlFileName>_<TimestampOfLastEventProcessed>_<Int32.MaxValue>.dtr
            //
            // Using Int32.MaxValue as a component of the trace file name makes
            // it easy to identify gaps in the filtered traces if the DCA is
            // falling behind on trace processing. Recall that an inactive ETL
            // file is always processed fully. Only active ETL files are processed
            // in chunks. Therefore, the presence of Int32.MaxValue indicates that
            // the corresponding ETL file is inactive and has been fully processed
            // by the DCA. Thus, gaps **within** an ETL file (i.e. unprocessed
            // chunks within the file) can be identified by the absence of a file
            // containing Int32.MaxValue in its name.
            //
            // It is also worth noting that ETL file names are sequentially
            // numbered, which helps in identifying gaps **between** ETL files
            // (i.e. ETL files that were not processed at all). And the use of
            // Int32.MaxValue is an enhancement that enables us to identify gaps
            // within an ETL file. Using these two concepts, we can look at a set
            // of filtered trace files and determine whether they are complete.
            // And if not complete, we can also identify where all the gaps are.
            string differentiator = string.Format(
                CultureInfo.InvariantCulture,
                "{0:D10}",
                isActiveEtl ? this.lastEventIndex.TimestampDifferentiator : int.MaxValue);
            string traceFileNamePrefix = string.Format(
                CultureInfo.InvariantCulture,
                "{0}_{1}_{2:D20}_{3}.",
                this.fabricNodeId,
                Path.GetFileNameWithoutExtension(fileName),
                this.lastEventIndex.Timestamp.Ticks,
                differentiator);

            var applicationInstanceId = ContainerEnvironment.GetContainerApplicationInstanceId(this.LogSourceId);

            if (ContainerEnvironment.IsContainerApplication(applicationInstanceId))
            {
                // Note that the a hash of the applicationInstanceId is being used to reduce file name length in around 70 characters
                // This is done to workaround PathTooLong exception in FileUploaderBase.cs since we don't have an interop for FileSystemWatcher
                // and .NET 4.5 used does not support long paths yet.
                traceFileNamePrefix = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}_{1:X8}_{2}_{3:D20}_{4}.",
                    this.fabricNodeId,
                    Path.GetFileName(applicationInstanceId).GetHashCode(),
                    Path.GetFileNameWithoutExtension(fileName),
                    this.lastEventIndex.Timestamp.Ticks,
                    differentiator);
            }

            string traceFileNameWithoutPath = string.Concat(
                traceFileNamePrefix,
                EtlConsumerConstants.FilteredEtwTraceFileExtension);
            string compressedTraceFileNameWithoutPath = string.Concat(
                traceFileNamePrefix,
                EtlConsumerConstants.FilteredEtwTraceFileExtension,
                EtlConsumerConstants.CompressedFilteredEtwTraceFileExtension);
            string subFolder = this.GetTraceFileSubFolder(fileName);
            string traceFileDestinationPath = Path.Combine(
                this.filteredTraceDirName,
                subFolder);
            string traceFileDestinationName = Path.Combine(
                traceFileDestinationPath,
                this.compressCsvFiles ? compressedTraceFileNameWithoutPath : traceFileNameWithoutPath);
            string alternateTraceFileDestinationName = Path.Combine(
                traceFileDestinationPath,
                this.compressCsvFiles ? traceFileNameWithoutPath : compressedTraceFileNameWithoutPath);

            // If a file with the same name already exists at the destination,
            // then don't copy the file over. This is because if the file already
            // existed at the destination, then the file that are about to copy
            // over must be a zero-byte file because we always ignore events that
            // we have already processed. Therefore, we don't want to overwrite
            // a file that contains events with a zero-byte file.
            if (InternalFileSink.FileExists(traceFileDestinationName) ||
                InternalFileSink.FileExists(alternateTraceFileDestinationName))
            {
                Debug.Assert(0 == this.fileSink.WriteStatistics.EventsWritten, "The temporary trace file must be a zero-byte file.");

                // Also, the ETL file must be an inactive ETL file because if it
                // had been an active ETL file and the temporary trace file was
                // empty, then we would have already returned from this method
                // due to a check made at the beginning of this method.
                Debug.Assert(false == isActiveEtl, "File must be inactive.");
                return;
            }

            // Copy the file
            try
            {
                InternalFileSink.CopyFile(this.fileSink.TempFileName, traceFileDestinationName, false, this.compressCsvFiles);

                // logging bytes read and written
                var fileInfo = new FileInfo(this.fileSink.TempFileName);
#if !DotNetCoreClr
                this.perfHelper.BytesRead(fileInfo.Length);
                this.perfHelper.BytesWritten(fileInfo.Length);
#endif

                this.TraceSource.WriteInfo(
                    this.LogSourceId,
                    "Filtered traces from {0} are ready. They have been moved from {1} to {2}.",
                    fileName,
                    this.fileSink.TempFileName,
                    traceFileDestinationName);
            }
            catch (Exception e)
            {
                // Log an error and move on
                this.TraceSource.WriteExceptionAsError(
                    this.LogSourceId,
                    e,
                    "Failed to copy file. Source: {0}, destination: {1}.",
                    this.fileSink.TempFileName,
                    traceFileDestinationName);
            }
        }
예제 #10
0
        public static int Main(string[] args)
        {
            Utility.TraceSource = null;

#if !DotNetCoreClr
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
#endif

#if !DotNetCoreClrLinux && !DotNetCoreClrIOT
            // Register an unhandled exception event handler
            AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler.OnUnhandledException;
#endif

            // Initialize config store
            ConfigUpdateHandler configUpdateHandler = new ConfigUpdateHandler();
            Utility.InitializeConfigStore(configUpdateHandler);

            // Initialize the Fabric node Id
            Utility.InitializeFabricNodeInfo();

            // Read FabricHost's exit failure reset time from settings
            UnhandledExceptionHandler.ReadFabricHostExitFailureResetTime();

            // Set up tracing
            Utility.InitializeTracing();
            Utility.TraceSource = new FabricEvents.ExtensionsEvents(FabricEvents.Tasks.FabricDCA);

            Utility.DcaProgramDirectory = Path.Combine(Path.GetDirectoryName(FabricEnvironment.GetCodePath()), "DCA.Code");

            // Initialize the work directory
            Utility.InitializeWorkDirectory();

            // Create the event that indicates when the main thread should
            // stop the DCA
            stopDCAEvent = new ManualResetEvent(false);
            UnhandledExceptionHandler.StopDcaEvent = stopDCAEvent;

            // Create the event that indicates that the main thread has
            // stopped the DCA.
            dcaHasStoppedEvent = new ManualResetEvent(false);

            // Register to be notified when we need to stop.
            Console.CancelKeyPress += CtrlCHandler;

            // The configuration update handler makes use of some members that we just
            // initialized above, e.g. the trace source and the event used to indicate
            // that the DCA should stop.
            //
            // Until we initialize these members, it is not safe for the the configuration
            // update handler to process any updates because it would end up trying to
            // access those uninitialized members. Therefore the configuration update
            // handler ignores these updates until this point. This is okay, because we
            // haven't attempted to read configurations until now. When we read the
            // configurations later, we will be reading the updated values anyway, so
            // ignoring the update notifications is not a problem.
            //
            // Now that we have initialized all the members needed by the configuration
            // update handler, we tell it to start processing configuration updates.
            configUpdateHandler.StartProcessingConfigUpdates();

            // Create and initialize the application instance manager object.
            AppInstanceManager appInstanceMgr = new AppInstanceManager();

            // Notify the application instance manager about the availability of the
            // Windows Fabric application.
            appInstanceMgr.CreateApplicationInstance(Utility.WindowsFabricApplicationInstanceId, null);

            // Let the config update handler know that the Windows Fabric
            // Application has been created, so that it can send configuration
            // updates if it needs to.
            configUpdateHandler.StartConfigUpdateDeliveryToAppInstanceMgr(appInstanceMgr);

            // Create and initialize the service package table manager object
            ServicePackageTableManager servicePackageTableManager = new ServicePackageTableManager(appInstanceMgr);

            // Create and initialize the container manager object if required.
            ContainerManager     containerManager     = null;
            ContainerEnvironment containerEnvironment = null;

            // FabricContainerAppsEnabled is set to true by default
            bool enableContainerManager = Utility.GetUnencryptedConfigValue <bool>(
                ConfigReader.HostingSectionName,
                ConfigReader.FabricContainerAppsEnabledParameterName,
                true);

            if (enableContainerManager)
            {
                containerEnvironment = new ContainerEnvironment();
                containerManager     = new ContainerManager(appInstanceMgr, containerEnvironment);
            }

            // DCA is running again.
            HealthClient.ClearNodeHealthReport();

            // Wait for the event that is signaled when the DCA needs to be
            // stopped.
            stopDCAEvent.WaitOne();

            // Stop the DCA's periodic activities
            Utility.TraceSource.WriteInfo(
                TraceType,
                "Stopping the DCA ...");

            servicePackageTableManager.Dispose();
            configUpdateHandler.Dispose();
            appInstanceMgr.Dispose();

            Utility.TraceSource.WriteInfo(
                TraceType,
                "DCA has stopped.");

            // Set event to indicate that the main thread has stopped the DCA
            bool result = dcaHasStoppedEvent.Set();
            System.Fabric.Interop.Utility.ReleaseAssert(
                result,
                StringResources.DCAError_SignalEventToStopFailed);

            return(0);
        }
예제 #11
0
        private static Dictionary <string, IDcaConsumer> CreateConsumers(
            ConsumerFactory consumerFactory,
            IDictionary <string, List <object> > producerConsumerMap,
            DCASettings settings,
            DiskSpaceManager diskSpaceManager,
            string applicationInstanceId,
            IList <string> errorEvents)
        {
            // Initialize consumer instance list
            var consumers = new Dictionary <string, IDcaConsumer>();

            foreach (string consumerInstance in settings.ConsumerInstances.Keys)
            {
                // Get the consumer instance information
                DCASettings.ConsumerInstanceInfo consumerInstanceInfo = settings.ConsumerInstances[consumerInstance];

                // Prepare the consumer initialization parameters
                var initParam = new ConsumerInitializationParameters(
                    applicationInstanceId,
                    consumerInstanceInfo.SectionName,
                    Utility.FabricNodeId,
                    Utility.FabricNodeName,
                    Utility.LogDirectory,
                    Utility.DcaWorkFolder,
                    diskSpaceManager);

                // if the application is a container move to container log folder.
                if (ContainerEnvironment.IsContainerApplication(applicationInstanceId))
                {
                    initParam = new ConsumerInitializationParameters(
                        applicationInstanceId,
                        consumerInstanceInfo.SectionName,
                        Utility.FabricNodeId,
                        Utility.FabricNodeName,
                        ContainerEnvironment.GetContainerLogFolder(applicationInstanceId),
                        Utility.DcaWorkFolder,
                        diskSpaceManager);
                }

                // Create consumer instance
                IDcaConsumer consumerInterface;
                try
                {
                    consumerInterface = consumerFactory.CreateConsumer(
                        consumerInstance,
                        initParam,
                        consumerInstanceInfo.TypeInfo.AssemblyName,
                        consumerInstanceInfo.TypeInfo.TypeName);
                }
                catch (Exception e)
                {
                    // We should continue trying to create other consumers.
                    errorEvents.Add(e.Message);
                    continue;
                }

                // Get the consumer's data sink
                object sink = consumerInterface.GetDataSink();
                if (null == sink)
                {
                    // The consumer does not wish to provide a data sink.
                    // One situation this might happen is if the consumer has been
                    // disabled. This is not an error, so just move on to the next
                    // consumer.
                    continue;
                }

                // Add the data sink to the corresponding producer's consumer sink list
                string producerInstance = consumerInstanceInfo.ProducerInstance;
                Debug.Assert(false == string.IsNullOrEmpty(producerInstance), "Consumers must be tied to a producer");
                if (false == producerConsumerMap.ContainsKey(producerInstance))
                {
                    producerConsumerMap[producerInstance] = new List <object>();
                }

                producerConsumerMap[producerInstance].Add(sink);

                // Add the consumer to the consumer list
                consumers[consumerInstance] = consumerInterface;
            }

            return(consumers);
        }
예제 #12
0
        private static Dictionary <string, IDcaProducer> CreateProducers(
            ProducerFactory producerFactory,
            IDictionary <string, List <object> > producerConsumerMap,
            DCASettings settings,
            string applicationInstanceId,
            IList <string> errorEvents)
        {
            // Initialize producer instance list
            var producers = new Dictionary <string, IDcaProducer>();

            Debug.Assert(null != producerConsumerMap, "Map of producers to consumers must be initialized.");

            foreach (string producerInstance in settings.ProducerInstances.Keys)
            {
                // Get the producer instance information
                DCASettings.ProducerInstanceInfo producerInstanceInfo = settings.ProducerInstances[producerInstance];

                // Prepare the producer initialization parameters
                ProducerInitializationParameters initParam = new ProducerInitializationParameters();
                initParam.ApplicationInstanceId = applicationInstanceId;
                initParam.SectionName           = producerInstanceInfo.SectionName;
                initParam.LogDirectory          = Utility.LogDirectory;

                if (ContainerEnvironment.IsContainerApplication(applicationInstanceId))
                {
                    if (producerInstanceInfo.TypeName != StandardPluginTypes.EtlFileProducer)
                    {
                        continue;
                    }

                    initParam.LogDirectory = ContainerEnvironment.GetContainerLogFolder(applicationInstanceId);
                }

                initParam.WorkDirectory = Utility.DcaWorkFolder;
                if (producerConsumerMap.ContainsKey(producerInstance))
                {
                    initParam.ConsumerSinks = producerConsumerMap[producerInstance];
                    producerConsumerMap.Remove(producerInstance);
                }
                else
                {
                    initParam.ConsumerSinks = null;
                }

                // Create producer instance
                try
                {
                    var producerInterface = producerFactory.CreateProducer(
                        producerInstance,
                        initParam,
                        producerInstanceInfo.TypeName);

                    // Add the producer to the producer list
                    producers[producerInstance] = producerInterface;
                }
                catch (Exception e)
                {
                    // Initialize the producer
                    Utility.TraceSource.WriteError(
                        TraceType,
                        "Failed to create producer {0}. {1}",
                        producerInstance,
                        e);
                    var message = string.Format(
                        StringResources.DCAError_UnhandledPluginExceptionHealthDescription,
                        producerInstanceInfo.SectionName,
                        e.Message);
                    errorEvents.Add(message);
                }
            }

            return(producers);
        }
예제 #13
0
        private bool TryGetContainerTraceFolder(out string containerTraceFolder)
        {
            containerTraceFolder = null;

            var applicationInstanceId = ContainerEnvironment.GetContainerApplicationInstanceId(this.logSourceId);

            if (ContainerEnvironment.IsContainerApplication(applicationInstanceId))
            {
                string containerTraceFolderParent = Path.Combine(
                    ContainerEnvironment.GetContainerLogFolder(applicationInstanceId),
                    LttProducerConstants.LttSubDirectoryUnderLogDirectory);

                IEnumerable <string> traceFolders = null;
                int numberOfTraceFolders;

                try
                {
                    traceFolders = Directory.EnumerateDirectories(
                        containerTraceFolderParent,
                        $"{LttProducerConstants.LttTraceSessionFolderNamePrefix}*");

                    numberOfTraceFolders = traceFolders.Count();
                }
                catch (OverflowException)
                {
                    this.traceSource.WriteWarning(this.logSourceId, $"Number of container trace folders found is too large.");
                    numberOfTraceFolders = int.MaxValue;
                }
                catch (Exception e)
                {
                    this.traceSource.WriteExceptionAsError(this.logSourceId, e, $"Exception when trying to get container trace folder");
                    return(false);
                }

                if (traceFolders == null)
                {
                    return(false);
                }

                switch (numberOfTraceFolders)
                {
                case 0:
                    this.traceSource.WriteWarning(this.logSourceId, "No LTTng traces folder found for container.");
                    containerTraceFolder = null;
                    break;

                case 1:
                    containerTraceFolder = traceFolders.First();
                    this.traceSource.WriteInfo(this.logSourceId, $"Processing LTTng traces from container at: {containerTraceFolder}");
                    break;

                default:
                    containerTraceFolder = traceFolders.FirstOrDefault();
                    this.traceSource.WriteWarning(this.logSourceId, $"Found {numberOfTraceFolders} container trace folders. Using {containerTraceFolder}");
                    break;
                }
                return(true);
            }

            return(false);
        }