private static IDictionary <string, string> ExtractServiceBusMessageProperties(IServiceBusMessage message)
        {
            var eventProperties = new Dictionary <string, string>();
            var attemptObject   = message.GetProperty(VstsMessageConstants.RetryAttemptPropertyName) ?? "0";
            int attempt;

            int.TryParse(attemptObject.ToString(), out attempt);
            attempt++;

            var taskLogIdObject = message.GetProperty(VstsMessageConstants.TaskLogIdPropertyName) ?? string.Empty;

            eventProperties[VstsMessageConstants.RetryAttemptPropertyName] = attempt.ToString();
            eventProperties[VstsMessageConstants.MessageIdPropertyName]    = message.GetMessageId();
            eventProperties[VstsMessageConstants.MachineNamePropertyName]  = Environment.MachineName;
            eventProperties[VstsMessageConstants.TaskLogIdPropertyName]    = taskLogIdObject.ToString();

            return(eventProperties);
        }
        private async Task <int> GetOrCreateTaskLogId(IServiceBusMessage message, CancellationToken cancellationToken, ITaskClient taskClient, Guid projectId, Guid planId, Guid jobId, Guid parentTimelineId, string timelineName, string hubName)
        {
            // attempt to get from message
            var logIdObject = message.GetProperty(VstsMessageConstants.TaskLogIdPropertyName);
            var taskLogId   = 0;
            var gotLogId    = logIdObject != null && int.TryParse(logIdObject.ToString(), out taskLogId);

            if (gotLogId)
            {
                return(taskLogId);
            }

            // attempt to find existing
            var records = await taskClient.GetRecordsAsync(projectId, hubName, planId, parentTimelineId, userState : null, cancellationToken : cancellationToken).ConfigureAwait(false);

            foreach (var record in records)
            {
                if (string.Equals(record.Name, timelineName, StringComparison.OrdinalIgnoreCase))
                {
                    return(record.Log.Id);
                }
            }

            // Create a new timeline
            var subTimelineId = Guid.NewGuid();

            // create a log file
            var logsSubtimelineId = string.Format(@"logs\{0:D}", subTimelineId);
            var taskLog           = await taskClient.CreateLogAsync(projectId, hubName, planId, new TaskLog(logsSubtimelineId), userState : null, cancellationToken : cancellationToken).ConfigureAwait(false);

            // create a sub-timeline
            var timelineRecord = new TimelineRecord
            {
                Id              = subTimelineId,
                Name            = timelineName,
                StartTime       = DateTime.UtcNow,
                State           = TimelineRecordState.InProgress,
                RecordType      = "task", // Record type can be job or task, as we will be dealing only with task here
                WorkerName      = this.settings.WorkerName,
                Order           = 1,      // The job timeline record must be at order 1
                Log             = taskLog,
                ParentId        = jobId,
                PercentComplete = 0,
                ErrorCount      = 0,
                WarningCount    = 0
            };

            await taskClient.UpdateTimelineRecordsAsync(projectId, hubName, planId, parentTimelineId, new List <TimelineRecord> {
                timelineRecord
            }, cancellationToken).ConfigureAwait(false);

            // save the taskLogId on the message
            taskLogId = taskLog.Id;

            return(taskLogId);
        }