public override kCura.EventHandler.Response Execute()
        {
            // Update Security Protocol
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <PreInstallEventHandler>();

            // Init general response
            kCura.EventHandler.Response response = new kCura.EventHandler.Response()
            {
                Success = true,
                Message = ""
            };

            // Get current Workspace ID
            int workspaceId = this.Helper.GetActiveCaseID();

            _logger.LogDebug("Audit Log Elastic Search, current Workspace ID: {workspaceId}", workspaceId.ToString());

            // Get database context of the instance
            IDBContext instanceContext = Helper.GetDBContext(-1);

            // Current Relativity version
            string currentRelativityVersion = "";

            try
            {
                // Get Relativity version
                currentRelativityVersion = instanceContext.ExecuteSqlStatementAsScalar("SELECT [Value] FROM [eddsdbo].[Relativity] WHERE [Key] = 'Version'").ToString();
                _logger.LogDebug("Audit Log Elastic Search, current Relativity version: {version}", currentRelativityVersion);
                _logger.LogDebug("Audit Log Elastic Search, minimum required Relativity version: {version}", this.MinRelativityVersion);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Pre Install EventHandler Relativity version error");

                response.Success = false;
                response.Message = "Pre Install EventHandler Relativity version error";
                return(response);
            }

            // Check Relativity version requirements
            if (new Version(currentRelativityVersion) < new Version(this.MinRelativityVersion))
            {
                _logger.LogError("Audit Log Elastic Search, old Relativity instance (version: {version})", currentRelativityVersion);

                response.Success = false;
                response.Message = string.Format("This application requires Relativity {0} or later", this.MinRelativityVersion);
                return(response);
            }

            // Log end of Pre Install EventHandler
            _logger.LogDebug("Audit Log Elastic Search, Pre Install EventHandler successfully finished");

            return(response);
        }
Esempio n. 2
0
        /*
         * Occurs after the user has selected items and pressed go.
         * In this function you can validate the items selected and return a warning/error message.
         */
        public override kCura.EventHandler.Response ValidateSelection()
        {
            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <MassOperationHandler>();

            // Init general response
            kCura.EventHandler.Response response = new kCura.EventHandler.Response()
            {
                Success = true,
                Message = ""
            };

            // Get current Workspace ID
            int workspaceId = this.Helper.GetActiveCaseID();

            _logger.LogDebug("Azure Translator, current Workspace ID: {workspaceId}", workspaceId.ToString());

            // Check if all Instance Settings are in place
            IDictionary <string, string> instanceSettings = this.GetInstanceSettings(ref response, new string[] { "SourceField", "DestinationField", "LogField", "Cost1MCharacters", "AzureServiceRegion", "AzureSubscriptionKey", "AzureTranslatorEndpoint", "TranslateFrom", "TranslateTo" });

            // Check if there was not error
            if (!response.Success)
            {
                return(response);
            }

            /*
             * Calculate the translation costs
             */
            // TODO: redo in Object Manager API
            try
            {
                // Construct and execute SQL Query to get the characters count
                string sqlText = "SELECT SUM(LEN(CAST([" + instanceSettings["SourceField"].Replace(" ", "") + "] AS NVARCHAR(MAX)))) FROM [EDDSDBO].[Document] AS [Document] JOIN [Resource].[" + this.MassActionTableName + "] AS [MassActionTableName] ON [Document].[ArtifactID] = [MassActionTableName].[ArtifactID]";
                _logger.LogDebug("Azure Translator, translation cost SQL Parameter and Query: {query}", sqlText);
                long count = (long)this.Helper.GetDBContext(workspaceId).ExecuteSqlStatementAsScalar(sqlText);

                // Calculate translation cost
                float cost = (count / 1000000f) * float.Parse(instanceSettings["Cost1MCharacters"]);
                _logger.LogDebug("Azure Translator, translation cost: {price}CHF, ({chars} chars)", cost.ToString("0.00"), count.ToString());
                response.Message = string.Format("Translation cost is {0}CHF, ({1} chars)", cost.ToString("0.00"), count.ToString());
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Azure Translator, translation cost error ({SourceField}, {Cost1MCharacters})", instanceSettings["SourceField"], instanceSettings["Cost1MCharacters"]);

                response.Success = false;
                response.Message = "Translation cost error";
            }

            return(response);
        }
Esempio n. 3
0
        /*
         * Custom method to get required Relativity Instance Settings
         */
        private IDictionary <string, string> GetInstanceSettings(ref kCura.EventHandler.Response response, string[] instanceSettingsNames)
        {
            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <MassOperationHandler>();

            // Output Dictionary
            IDictionary <string, string> instanceSettingsValues = new Dictionary <string, string>();

            // Get and validate instance settings
            foreach (string name in instanceSettingsNames)
            {
                try
                {
                    instanceSettingsValues.Add(name, this.Helper.GetInstanceSettingBundle().GetString("Azure.Translator", name));
                    if (instanceSettingsValues[name].Length <= 0)
                    {
                        _logger.LogError("Azure Translator, Instance Settings empty error: {section}/{name}", "Azure.Translator", name);

                        response.Success = false;
                        response.Message = "Instance Settings error";
                        return(instanceSettingsValues);
                    }
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "Azure Translator, Instance Settings error: {section}/{name}", "Azure.Translator", name);

                    response.Success = false;
                    response.Message = "Instance Settings error";
                    return(instanceSettingsValues);
                }

                _logger.LogDebug("Azure Translator, Instance Setting: {name}=>{value}", name, instanceSettingsValues[name]);
            }

            // Check Cost1MCharacters Instance Settings is a number
            try
            {
                float.Parse(instanceSettingsValues["Cost1MCharacters"]);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Azure Translator, Instance Settings error: {section}/{name}", "Azure.Translator", "Cost1MCharacters");

                response.Success = false;
                response.Message = "Instance Settings error";
                return(instanceSettingsValues);
            }

            return(instanceSettingsValues);
        }
        public override kCura.EventHandler.Response Execute()
        {
            // Update Security Protocol
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <PreUninstallEventHandler>();

            // Init general response
            kCura.EventHandler.Response response = new kCura.EventHandler.Response()
            {
                Success = true,
                Message = ""
            };

            // Get current Workspace ID
            int workspaceId = this.Helper.GetActiveCaseID();

            _logger.LogDebug("Audit Log Elastic Search, current Workspace ID: {workspaceId}", workspaceId.ToString());

            // Get database context of the instance
            IDBContext instanceContext = Helper.GetDBContext(-1);

            // Update line of the application management and set current workspace to disabled
            try
            {
                // Update the application management table
                SqlParameter workspaceIdParam = new SqlParameter("@workspaceId", workspaceId);
                instanceContext.ExecuteNonQuerySQLStatement("UPDATE [eddsdbo].[" + this.TableName + "] SET [Status] = 0, [LastUpdated] = CURRENT_TIMESTAMP WHERE [CaseArtifactID] = @workspaceId", new SqlParameter[] { workspaceIdParam });
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Pre Uninstall EventHandler application management table update error");

                response.Success = false;
                response.Message = "Pre Uninstall EventHandler application management table update error";
                return(response);
            }

            // Log end of Pre Uninstall EventHandler
            _logger.LogDebug("Audit Log Elastic Search, Pre Uninstall EventHandler successfully finished");

            return(response);
        }
        public override kCura.EventHandler.Response Execute()
        {
            // Update Security Protocol
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <PostWorkspaceCreateEventHandlerBase>();

            // Init general response
            kCura.EventHandler.Response response = new kCura.EventHandler.Response()
            {
                Success = true,
                Message = ""
            };

            // Get current Workspace ID
            int workspaceId = this.Helper.GetActiveCaseID();

            _logger.LogDebug("Audit Log Elastic Search, current Workspace ID: {workspaceId}", workspaceId.ToString());

            // Get database context of the instance
            IDBContext instanceContext = Helper.GetDBContext(-1);

            // Add line to the application management table for current workspace
            try
            {
                // Insert to the application management table
                SqlParameter workspaceIdParam = new SqlParameter("@workspaceId", workspaceId);
                instanceContext.ExecuteNonQuerySQLStatement("INSERT INTO [eddsdbo].[" + this.TableName + "] ([CaseArtifactID], [AuditRecordID], [Status], [LastUpdated]) VALUES (@workspaceId, 0, 1, CURRENT_TIMESTAMP)", new SqlParameter[] { workspaceIdParam });
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Post Workspace Create EventHandler application management table insert error");

                response.Success = false;
                response.Message = "Post Workspace Create EventHandler application management table insert error";
                return(response);
            }

            // Log end of Post Workspace Create EventHandler
            _logger.LogDebug("Audit Log Elastic Search, Post Workspace Create EventHandler successfully finished");

            return(response);
        }
Esempio n. 6
0
        public override kCura.EventHandler.Response Execute()
        {
            // Update Security Protocol
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <PostInstallEventHandler>();

            // Init general response
            kCura.EventHandler.Response response = new kCura.EventHandler.Response()
            {
                Success = true,
                Message = ""
            };

            // Get current Workspace ID
            int workspaceId = this.Helper.GetActiveCaseID();

            _logger.LogDebug("Audit Log Elastic Search, current Workspace ID: {workspaceId}", workspaceId.ToString());

            // Get database context of the instance
            IDBContext instanceContext = Helper.GetDBContext(-1);

            // Existing application management table name
            string tableExisting = "";

            try
            {
                // Get application management table
                tableExisting = instanceContext.ExecuteSqlStatementAsScalar("SELECT ISNULL((SELECT '" + this.TableName + "' FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_SCHEMA] = 'eddsdbo' AND [TABLE_NAME] = '" + this.TableName + "'), '')").ToString();
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Post Install EventHandler application management table error");

                response.Success = false;
                response.Message = "Post Install EventHandler management application table error";
                return(response);
            }

            // If application management table not present, create it
            if (tableExisting != this.TableName)
            {
                instanceContext.BeginTransaction();
                try
                {
                    // Create application management table
                    instanceContext.ExecuteNonQuerySQLStatement("CREATE TABLE [eddsdbo].[" + this.TableName + "] ([CaseArtifactID] [int] NOT NULL, [AuditRecordID] [bigint] NOT NULL, [Status] [bit] NOT NULL, [LastUpdated] [datetime] NOT NULL, [AgentArtifactID] [int] NULL)");
                    instanceContext.CommitTransaction();
                }
                catch (Exception e)
                {
                    instanceContext.RollbackTransaction();

                    _logger.LogError(e, "Audit Log Elastic Search, Post Install EventHandler application management table creation error");

                    response.Success = false;
                    response.Message = "Post Install EventHandler application management table creation error";
                    return(response);
                }
            }

            // Add line to the application management table for current workspace
            try
            {
                // Insert to the application management table
                SqlParameter workspaceIdParam = new SqlParameter("@workspaceId", workspaceId);
                instanceContext.ExecuteNonQuerySQLStatement("INSERT INTO [eddsdbo].[" + this.TableName + "] ([CaseArtifactID], [AuditRecordID], [Status], [LastUpdated]) VALUES (@workspaceId, 0, 1, CURRENT_TIMESTAMP)", new SqlParameter[] { workspaceIdParam });
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Post Install EventHandler application management table insert error");

                response.Success = false;
                response.Message = "Post Install EventHandler application management table insert error";
                return(response);
            }

            // Log end of Post Install EventHandler
            _logger.LogDebug("Audit Log Elastic Search, Post Install EventHandler successfully finished");

            return(response);
        }
Esempio n. 7
0
        /*
         * Custom method to translate document using Azure Translator
         */
        private async Task <int> TranslateDocument(int workspaceId, int documentArtifactId, string sourceField, string destinationField, string logField, string azureServiceRegion, string azureSubscriptionKey, string azureTranslatorEndpoint, string translateFrom, string translateTo)
        {
            /*
             * Custom local function to split string into chunks of defined size with delimiter priority
             */
            List <string> SplitMulti(string str, char[] delimiters, int minChunkThreshold, int maxChunkThreshold, int smallChunkThreshold)
            {
                List <string> chunks = new List <string>()
                {
                    str
                };
                List <string> subChunks;

                foreach (char delimiter in delimiters)
                {
                    for (int i = 0; i < chunks.Count; i++)
                    {
                        // Check if chunks are all below threshold otherwise split by space
                        if (chunks[i].Length > maxChunkThreshold)
                        {
                            subChunks = SplitSized(chunks[i], delimiter, minChunkThreshold, maxChunkThreshold, smallChunkThreshold);
                            chunks.RemoveAt(i);
                            chunks.InsertRange(i, subChunks);
                        }
                    }
                }

                return(chunks);
            }

            /*
             * Custom local function to split string into chunks of defined size
             */
            List <string> SplitSized(string str, char delimiter, int minChunkThreshold, int maxChunkThreshold, int smallChunkThreshold)
            {
                string[]      split  = str.Split(delimiter);
                List <string> chunks = new List <string>();

                string hlp = split[0];

                for (int i = 1; i < split.Length; i++)
                {
                    // Rearange split text into bigger chunks
                    if (((hlp.Length + split[i].Length) < minChunkThreshold || split[i].Length < smallChunkThreshold) && ((hlp.Length + split[i].Length) < maxChunkThreshold))
                    {
                        hlp = hlp + delimiter + split[i];
                    }
                    else
                    {
                        chunks.Add(hlp + delimiter);
                        hlp = split[i];
                    }
                }
                chunks.Add(hlp);

                return(chunks);
            }

            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <MassOperationHandler>();

            // Get Relativity Object Manager API
            IObjectManager objectManager = this.Helper.GetServicesManager().CreateProxy <IObjectManager>(ExecutionIdentity.CurrentUser);

            // Get document text
            Stream streamToTranslate;

            try
            {
                // Construct objects and retreive document content
                RelativityObjectRef relativityObject = new RelativityObjectRef
                {
                    ArtifactID = documentArtifactId
                };
                FieldRef relativityField = new FieldRef
                {
                    Name = sourceField
                };
                IKeplerStream keplerStream = await objectManager.StreamLongTextAsync(workspaceId, relativityObject, relativityField);

                streamToTranslate = await keplerStream.GetStreamAsync();
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Azure Translator, document for translation retrieval error (ArtifactID: {id})", documentArtifactId.ToString());
                return(documentArtifactId);
            }

            // Copy stream to text as that is used for further on
            string textToTranslate = new StreamReader(streamToTranslate).ReadToEnd();

            // Log original document
            _logger.LogDebug("Azure Translator, original document (ArtifactID: {id}, length: {length})", documentArtifactId.ToString(), textToTranslate.Length.ToString());

            // Split document text to chunks as Azure Translator request is limited by 10K characters
            List <string> partsToTranslate = SplitMulti(textToTranslate, new char[] { '.', ' ' }, 9000, 9900, 20);

            _logger.LogDebug("Azure Translator, document split into {n} parts (ArtifactID: {id})", partsToTranslate.Count.ToString(), documentArtifactId.ToString());

            // Force TLS 1.2 or higher as Azure requires it
            ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 & ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);

            // URL encode request paramenters
            translateFrom = WebUtility.HtmlEncode(translateFrom.ToLower());
            translateTo   = WebUtility.HtmlEncode(translateTo.ToLower());

            // Do Azure Translator call for every text part
            List <string> partsTranslated = new List <string>();

            for (int i = 0; i < partsToTranslate.Count; i++)
            {
                // Build translation request
                HttpRequestMessage request = new HttpRequestMessage();
                request.Method     = HttpMethod.Post;
                request.RequestUri = new Uri(azureTranslatorEndpoint + "translate?api-version=3.0&to=" + translateTo + (translateFrom == "auto" ? "" : "&from=" + translateFrom) + "&includeAlignment=true");  // https://docs.microsoft.com/azure/cognitive-services/translator/reference/v3-0-translate
                request.Content    = new StringContent(JsonConvert.SerializeObject(new object[] { new { Text = partsToTranslate[i] } }), Encoding.UTF8, "application/json");
                request.Headers.Add("Ocp-Apim-Subscription-Key", azureSubscriptionKey);
                request.Headers.Add("Ocp-Apim-Subscription-Region", azureServiceRegion);

                // Send the request
                HttpClient          client   = new HttpClient();
                HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false);

                // Check the response
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    _logger.LogError("Azure Translator, HTTP reposnse error (ArtifactID: {id}, status: {status})", documentArtifactId.ToString(), response.StatusCode.ToString());
                    return(documentArtifactId);
                }

                // Read the response
                string partTranslated = await response.Content.ReadAsStringAsync();

                _logger.LogDebug("Azure Translator, translation result JSON check (ArtifactID: {id}, length: {length})", documentArtifactId.ToString(), partTranslated.Length.ToString());
                client.Dispose();

                // Parse JSON
                TranslationResult[] translationResults = JsonConvert.DeserializeObject <TranslationResult[]>(partTranslated);

                // Check the translation result
                if (translationResults.Length > 1 || translationResults[0].Translations.Length > 1)
                {
                    _logger.LogError("Azure Translator, unexpected document translation results (ArtifactID: {id})", documentArtifactId.ToString());
                    return(documentArtifactId);
                }
                if (translationResults.Length == 0 || translationResults[0].Translations.Length == 0)
                {
                    _logger.LogError("Azure Translator, empty document translation results (ArtifactID: {id})", documentArtifactId.ToString());
                    return(documentArtifactId);
                }

                // Log the translation result
                _logger.LogDebug("Azure Translator, translation check (ArtifactID: {id}, part: {part}, length: {length})", documentArtifactId.ToString(), i.ToString(), translationResults[0].Translations[0].Text.Length.ToString());
                // Get the translation result
                partsTranslated.Add(translationResults[0].Translations[0].Text);
            }

            // Construct translated text
            string       textTranslated   = string.Join(string.Empty, partsTranslated);
            Stream       streamTranslated = new MemoryStream();
            StreamWriter streamWriter     = new StreamWriter(streamTranslated);

            streamWriter.Write(textTranslated);
            streamWriter.Flush();
            streamTranslated.Position = 0;

            // Log translated document
            _logger.LogDebug("Azure Translator, translated document (ArtifactID: {id}, length: {length})", documentArtifactId.ToString(), textTranslated.Length.ToString());

            // Update document translated text
            try
            {
                // Construct objects and do document update
                RelativityObjectRef relativityObject = new RelativityObjectRef
                {
                    ArtifactID = documentArtifactId
                };
                FieldRef relativityField = new FieldRef
                {
                    Name = destinationField
                };
                UpdateLongTextFromStreamRequest updateRequest = new UpdateLongTextFromStreamRequest
                {
                    Object = relativityObject,
                    Field  = relativityField
                };
                KeplerStream keplerStream = new KeplerStream(streamTranslated);
                await objectManager.UpdateLongTextFromStreamAsync(workspaceId, updateRequest, keplerStream);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Azure Translator, document for translation update error (ArtifactID: {id})", documentArtifactId.ToString());
                return(documentArtifactId);
            }

            // Update document translation log
            try
            {
                Stream streamCurrentLog;
                // Construct objects and get current translation log
                RelativityObjectRef relativityObject = new RelativityObjectRef
                {
                    ArtifactID = documentArtifactId
                };
                FieldRef relativityField = new FieldRef
                {
                    Name = logField
                };
                IKeplerStream keplerStream = await objectManager.StreamLongTextAsync(workspaceId, relativityObject, relativityField);

                streamCurrentLog = await keplerStream.GetStreamAsync();

                // Add new translation log
                Stream       streamUpdatedLog = new MemoryStream();
                StreamWriter streamLogWriter  = new StreamWriter(streamUpdatedLog);
                streamLogWriter.Write(new StreamReader(streamCurrentLog).ReadToEnd());
                streamLogWriter.Write("Azure Translator;" + this.Helper.GetAuthenticationManager().UserInfo.EmailAddress + ";" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + ";" + translateFrom + ";" + translateTo + ";" + textToTranslate.Length.ToString() + ";" + textTranslated.Length.ToString() + "\n");
                streamLogWriter.Flush();
                streamUpdatedLog.Position = 0;

                // Write updated translation log
                UpdateLongTextFromStreamRequest updateRequest = new UpdateLongTextFromStreamRequest
                {
                    Object = relativityObject,
                    Field  = relativityField
                };
                keplerStream = new KeplerStream(streamUpdatedLog);
                await objectManager.UpdateLongTextFromStreamAsync(workspaceId, updateRequest, keplerStream);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Azure Translator, translation log update error (ArtifactID: {id})", documentArtifactId.ToString());
                return(documentArtifactId);
            }

            // Return 0 as all went without error
            return(0);
        }
Esempio n. 8
0
        /*
         * This function is called in batches based on the size defined in configuration.
         */
        public override kCura.EventHandler.Response DoBatch()
        {
            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <MassOperationHandler>();

            // Init general response
            kCura.EventHandler.Response response = new kCura.EventHandler.Response()
            {
                Success = true,
                Message = ""
            };

            // Get current Workspace ID
            int workspaceId = this.Helper.GetActiveCaseID();

            _logger.LogDebug("Azure Translator, current Workspace ID: {workspaceId}", workspaceId.ToString());

            // Check if all Instance Settings are in place
            IDictionary <string, string> instanceSettings = this.GetInstanceSettings(ref response, new string[] { "SourceField", "DestinationField", "LogField", "Cost1MCharacters", "AzureServiceRegion", "AzureSubscriptionKey", "AzureTranslatorEndpoint", "TranslateFrom", "TranslateTo" });

            // Check if there was not error
            if (!response.Success)
            {
                return(response);
            }

            // Update general status
            this.ChangeStatus("Translating documents");

            // For each document create translation task
            List <Task <int> > translationTasks = new List <Task <int> >();
            int runningTasks    = 0;
            int concurrentTasks = 16;

            for (int i = 0; i < this.BatchIDs.Count; i++)
            {
                // Translate documents in Azure and update Relativity using Object Manager API
                translationTasks.Add(TranslateDocument(workspaceId, this.BatchIDs[i], instanceSettings["SourceField"], instanceSettings["DestinationField"], instanceSettings["LogField"], instanceSettings["AzureServiceRegion"], instanceSettings["AzureSubscriptionKey"], instanceSettings["AzureTranslatorEndpoint"], instanceSettings["TranslateFrom"], instanceSettings["TranslateTo"]));

                // Update progreass bar
                this.IncrementCount(1);

                // Allow only certain number of tasks to run concurrently
                do
                {
                    runningTasks = 0;
                    foreach (Task <int> translationTask in translationTasks)
                    {
                        if (!translationTask.IsCompleted)
                        {
                            runningTasks++;
                        }
                    }
                    if (runningTasks >= concurrentTasks)
                    {
                        Thread.Sleep(100);
                    }
                } while (runningTasks >= concurrentTasks);
            }

            // Update general status
            this.ChangeStatus("Waiting to finish the document translation");

            // Wait for all translations to finish
            _logger.LogDebug("Azure Translator, waiting for all documents finish translating ({n} document(s))", this.BatchIDs.Count.ToString());
            Task.WaitAll(translationTasks.ToArray());

            // Update general status
            this.ChangeStatus("Checking the results of the document translation");

            // Check results
            List <string> translationErrors = new List <string>();

            for (int i = 0; i < translationTasks.Count; i++)
            {
                // If translation was not done add to the error List
                _logger.LogDebug("Azure Translator, translation task result: {result} (task: {task})", translationTasks[i].Result.ToString(), translationTasks[i].Id.ToString());
                if (translationTasks[i].Result != 0)
                {
                    translationErrors.Add(translationTasks[i].Result.ToString());
                }
            }

            // If there are any errors adjust response
            if (translationErrors.Count > 0)
            {
                _logger.LogError("Azure Translator, not all documents have been translated: ({documents})", string.Join(", ", translationErrors));

                response.Success = false;
                response.Message = "Not all documents have been translated";
            }

            return(response);
        }
Esempio n. 9
0
        public override void Execute()
        {
            // Update Security Protocol
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            // Get logger
            Relativity.API.IAPILog _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext <Agent>();

            // Get current Agent ID
            int agentArtifactId = this.AgentID;

            _logger.LogDebug("Audit Log Elastic Search, current Agent ID: {agentArtifactId}", agentArtifactId.ToString());

            // Display initial message
            this.RaiseMessageNoLogging("Getting Instance Settings.", 10);

            // Get ES URI Instance Settings
            List <Uri> elasticUris = new List <Uri>();

            try
            {
                string[] uris = this.Helper.GetInstanceSettingBundle().GetString("Relativity.AuditLogElasticSearch", "ElasticSearchUris").Split(';');
                foreach (string uri in uris)
                {
                    if (Uri.IsWellFormedUriString(uri, UriKind.Absolute))
                    {
                        elasticUris.Add(new Uri(uri));
                    }
                    else
                    {
                        _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchUri), single URI error ({uri})", agentArtifactId.ToString(), uri);
                        this.RaiseMessageNoLogging(string.Format("Instance Settings error (ElasticSearchUri), single URI error ({0}).", uri), 1);
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchUri)", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Instance Settings error (ElasticSearchUri).", 1);
                return;
            }

            // Get ES authentication API Key Instance Settings
            string[] elasticApiKey = new string[] { "", "" };
            try
            {
                string apiKey = this.Helper.GetInstanceSettingBundle().GetString("Relativity.AuditLogElasticSearch", "ElasticSearchApiKey");
                if (apiKey.Length > 0)
                {
                    if (apiKey.Split(':').Length == 2)
                    {
                        elasticApiKey = apiKey.Split(':');
                    }
                    else
                    {
                        _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchApiKey), API Key format error ({apiKey})", agentArtifactId.ToString(), apiKey);
                        this.RaiseMessageNoLogging(string.Format("Instance Settings error (ElasticSearchApiKey), API Key format error ({0}).", apiKey), 1);
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchApiKey)", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Instance Settings error (ElasticSearchApiKey).", 1);
                return;
            }

            // Get ES index prefix Instance Settings (must by lowercase)
            string elasticIndexPrefix = "";

            try
            {
                elasticIndexPrefix = this.Helper.GetInstanceSettingBundle().GetString("Relativity.AuditLogElasticSearch", "ElasticSearchIndexPrefix").ToLower();
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchIndexPrefix)", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Instance Settings error (ElasticSearchIndexPrefix).", 1);
                return;
            }

            // Get ES index number of replicas Instance Settings
            int elasticIndexReplicas = 1;

            try
            {
                elasticIndexReplicas = this.Helper.GetInstanceSettingBundle().GetInt("Relativity.AuditLogElasticSearch", "ElasticSearchIndexReplicas").Value;
                if (elasticIndexReplicas < 0)
                {
                    elasticIndexReplicas = 1;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchIndexReplicas)", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Instance Settings error (ElasticSearchIndexReplicas).", 1);
                return;
            }

            // Get ES index number of shards Instance Settings
            int elasticIndexShards = 1;

            try
            {
                elasticIndexShards = this.Helper.GetInstanceSettingBundle().GetInt("Relativity.AuditLogElasticSearch", "ElasticSearchIndexShards").Value;
                if (elasticIndexShards < 0)
                {
                    elasticIndexShards = 1;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchIndexShards)", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Instance Settings error (ElasticSearchIndexShards).", 1);
                return;
            }

            // Get ES synchronization threshold for one agent run
            int elasticSyncSize = 1000;

            try
            {
                elasticSyncSize = this.Helper.GetInstanceSettingBundle().GetInt("Relativity.AuditLogElasticSearch", "ElasticSearchSyncSize").Value;
                if (elasticSyncSize < 1000)
                {
                    elasticSyncSize = 1000;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), Instance Settings error (ElasticSearchSyncSize)", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Instance Settings error (ElasticSearchSyncSize).", 1);
                return;
            }

            // Get database context of the instance
            IDBContext instanceContext = Helper.GetDBContext(-1);

            // Check if management table exists
            try
            {
                int exists = instanceContext.ExecuteSqlStatementAsScalar <int>("IF OBJECT_ID('[eddsdbo].[" + this.tableName + "]', 'U') IS NOT NULL SELECT 1 ELSE SELECT 0");
                _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), application management table " + (exists == 1 ? "exists" : "does not exist"), agentArtifactId.ToString());
                if (exists != 1)
                {
                    _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), application management table does not exist", agentArtifactId.ToString());
                    this.RaiseMessageNoLogging("Application management table does not exist.", 1);
                    return;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), application management table existence check error", agentArtifactId.ToString());
            }

            _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), selecting Workspace", agentArtifactId.ToString());
            this.RaiseMessageNoLogging("Selecting Workspace.", 10);

            // Check what needs to be done
            int  workspaceId   = -1;
            long auditRecordId = -1;
            int  status        = -1;

            instanceContext.BeginTransaction();
            try
            {
                // Get workspace that was synchronized latest
                DataTable dataTable = instanceContext.ExecuteSqlStatementAsDataTable(@"
                    SELECT TOP(1)
                        [CaseArtifactID],
                        [AuditRecordID],
                        [Status]
                    FROM [eddsdbo].[" + this.tableName + @"]
                    WHERE [AgentArtifactID] IS NULL
                    ORDER BY
                        [Status] ASC,
                        [LastUpdated] ASC
                ");

                // If there is no workspace check if table is empty and if it is, delete it
                _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), Workspace selection row count: {count}", agentArtifactId.ToString(), dataTable.Rows.Count.ToString());
                if (dataTable.Rows.Count == 0)
                {
                    int count = instanceContext.ExecuteSqlStatementAsScalar <int>("SELECT COUNT(*) FROM [eddsdbo].[" + this.tableName + "]");
                    _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), application management table row count: {count}", agentArtifactId.ToString(), count.ToString());
                    // If there are no rows in the application management table better to drop it
                    if (count == 0)
                    {
                        instanceContext.ExecuteNonQuerySQLStatement("DROP TABLE [eddsdbo].[" + this.tableName + "]");
                        _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), application management table was deleted", agentArtifactId.ToString());
                    }
                }
                // Else we have workspace to work with
                else
                {
                    DataRow dataRow = dataTable.Rows[0];
                    workspaceId   = Convert.ToInt32(dataRow["CaseArtifactID"]);
                    auditRecordId = Convert.ToInt64(dataRow["AuditRecordID"]);
                    status        = Convert.ToInt32(dataRow["Status"]);

                    // Update the application management table with Agent ID lock
                    SqlParameter agentArtifactIdParam = new SqlParameter("@agentArtifactId", agentArtifactId);
                    SqlParameter workspaceIdParam     = new SqlParameter("@workspaceId", workspaceId);
                    instanceContext.ExecuteNonQuerySQLStatement("UPDATE [eddsdbo].[" + this.tableName + "] SET [AgentArtifactID] = @agentArtifactId WHERE [CaseArtifactID] = @workspaceId", new SqlParameter[] { agentArtifactIdParam, workspaceIdParam });
                }
                instanceContext.CommitTransaction();
            }
            catch (Exception e)
            {
                instanceContext.RollbackTransaction();
                _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), application management table querying error", agentArtifactId.ToString());
                this.RaiseMessageNoLogging("Application management table querying error.", 1);
                return;
            }

            // If we have Workspace ID we have to do something
            if (workspaceId > 0)
            {
                // Construct ES index name
                string elasticIndexName = elasticIndexPrefix + workspaceId.ToString();

                // Construct connector to ES cluster
                Nest.ElasticClient elasticClient = null;
                try
                {
                    Elasticsearch.Net.StaticConnectionPool pool = new Elasticsearch.Net.StaticConnectionPool(elasticUris, true);
                    elasticClient = new Nest.ElasticClient(new Nest.ConnectionSettings(pool).DefaultIndex(elasticIndexName).ApiKeyAuthentication(elasticApiKey[0], elasticApiKey[1]).EnableHttpCompression());
                }
                catch (Exception e)
                {
                    this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                    _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}) Elastic Search connection call error ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                    this.RaiseMessageNoLogging(string.Format("Elastic Search connection call error ({0}, {1}).", string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName), 1);
                    return;
                }

                // Check ES cluster connection
                Nest.PingResponse pingResponse = elasticClient.Ping();
                if (pingResponse.IsValid)
                {
                    _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), Ping succeeded ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                }
                else
                {
                    this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                    _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), Ping failed, check cluster health and connection settings ({elasticUris}, {indexName}, {elasticError})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName, pingResponse.DebugInformation);
                    this.RaiseMessageNoLogging(string.Format("Elastic Search ping failed, check cluster health and connection settings ({0}, {1}, {2}).", string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName, pingResponse.DebugInformation), 1);
                    return;
                }

                switch (status)
                {
                // If the status is 0 we will be deleting ES index
                case 0:
                    _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), deleting ES index ({indexName})", agentArtifactId.ToString(), elasticIndexName);
                    this.RaiseMessageNoLogging(string.Format("Deleting ES index ({0}).", elasticIndexName), 10);

                    // Delete ES index
                    try
                    {
                        Nest.DeleteIndexResponse deleteIndexResponse = elasticClient.Indices.Delete(elasticIndexName);
                        if (deleteIndexResponse.Acknowledged)
                        {
                            _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), Elastic Search index deleted ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                        }
                        else
                        {
                            this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                            _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), Elastic Search index deletion error ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                            this.RaiseMessageNoLogging(string.Format("Elastic Search index deletion error ({0}, {1}).", string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName), 1);
                            return;
                        }
                    }
                    catch (Exception e)
                    {
                        this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                        _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}) Elastic Search deletion call error ({indexName})", agentArtifactId.ToString(), elasticIndexName);
                        this.RaiseMessageNoLogging(string.Format("Elastic Search deletion call error ({0}).", elasticIndexName), 1);
                        return;
                    }

                    // Delete related row from the application management table
                    try
                    {
                        SqlParameter workspaceIdParam = new SqlParameter("@workspaceId", workspaceId);
                        instanceContext.ExecuteNonQuerySQLStatement("DELETE FROM [eddsdbo].[" + this.tableName + "] WHERE [Status] = 0 AND [CaseArtifactID] = @workspaceId", new SqlParameter[] { workspaceIdParam });
                    }
                    catch (Exception e)
                    {
                        this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                        _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}), application management table delete error", agentArtifactId.ToString());
                        this.RaiseMessageNoLogging("Application management table delete error.", 1);
                        return;
                    }
                    break;

                // If the status is 1 we will be synchronizing Audit Log with ES index
                case 1:
                    _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), synchronizing Audit Log of Workspace ({workspaceId}) to ES index ({indexName})", agentArtifactId.ToString(), workspaceId.ToString(), elasticIndexName);
                    this.RaiseMessageNoLogging(string.Format("Synchronizing Audit Log of Workspace ({0}) to ES index ({1})", workspaceId.ToString(), elasticIndexName), 10);

                    // If there is no records synchronized yet, we have to create ES index first
                    if (auditRecordId == 0)
                    {
                        // Create ES index
                        try {
                            Nest.CreateIndexResponse createIndexResponse = elasticClient.Indices.Create(elasticIndexName, c => c.Settings(s => s.NumberOfShards(elasticIndexShards).NumberOfReplicas(elasticIndexReplicas)).Map <AuditRecord>(m => m.AutoMap()));
                            if (createIndexResponse.Acknowledged)
                            {
                                _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), Elastic Search index created ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                            }
                            else
                            {
                                this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                                _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), Elastic Search index creation error ({elasticUris}, {indexName}, {serverError})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName, createIndexResponse.ServerError.ToString());
                                this.RaiseMessageNoLogging(string.Format("Elastic Search index creation error ({0}, {1}).", string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName), 1);
                                return;
                            }
                        }
                        catch (Exception e)
                        {
                            this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                            _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}) Elastic Search index creation call error ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                            this.RaiseMessageNoLogging(string.Format("Elastic Search index creation call error ({0}, {1}).", string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName), 1);
                            return;
                        }
                    }

                    // Get database context of the given workspace
                    IDBContext workspaceContext = Helper.GetDBContext(workspaceId);

                    // Synchronize until threshold is reached
                    int syncCount = 0;
                    while (syncCount < elasticSyncSize)
                    {
                        try
                        {
                            // Get Audit Log to synchronize
                            SqlParameter auditRecordIdParam = new SqlParameter("@auditRecordId", auditRecordId);
                            DataTable    dataTable          = workspaceContext.ExecuteSqlStatementAsDataTable(@"
                                    SELECT TOP (1000)
	                                    [AuditRecord].[ID],
	                                    [AuditRecord].[TimeStamp],
	                                    [AuditRecord].[ArtifactID],
	                                    [AuditRecord].[Action] AS [ActionID],
	                                    [AuditAction].[Action],
	                                    [AuditRecord].[UserID],
	                                    [AuditUser].[FullName] AS [User],
	                                    [AuditRecord].[ExecutionTime],
	                                    [AuditRecord].[Details],
	                                    [AuditRecord].[RequestOrigination],
	                                    [AuditRecord].[RecordOrigination]
                                    FROM [EDDSDBO].[AuditRecord] WITH (NOLOCK)
                                    JOIN [EDDSDBO].[AuditUser] WITH (NOLOCK) ON [AuditRecord].[UserID] = [AuditUser].[UserID]
                                    JOIN [EDDSDBO].[AuditAction] WITH (NOLOCK) ON [AuditRecord].[Action] = [AuditAction].[AuditActionID]
                                    WHERE [AuditRecord].[ID] > @auditRecordId
                                    ORDER BY [AuditRecord].[ID] ASC
                                ", new SqlParameter[] { auditRecordIdParam });

                            // If there is nothing to synchronize end
                            _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), Audit Log row count to synchronize: {count}", agentArtifactId.ToString(), dataTable.Rows.Count.ToString());
                            if (dataTable.Rows.Count == 0)
                            {
                                // Log end of Agent execution
                                this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                                _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), completed, nothing to synchronize", agentArtifactId.ToString());
                                this.RaiseMessageNoLogging("Completed.", 10);
                                return;
                            }
                            // Else synchronize workspace Audit Log with ES index
                            else
                            {
                                // Synchronizing workspace Audit Log with ES index
                                List <AuditRecord> auditRecords = new List <AuditRecord>();
                                long newAuditRecordId           = auditRecordId;
                                for (int i = 0; i < dataTable.Rows.Count; i++)
                                {
                                    // Read Audit Log data
                                    AuditRecord auditRecord = new AuditRecord();
                                    DataRow     dataRow     = dataTable.Rows[i];
                                    auditRecord.AuditRecordId = Convert.ToInt64(dataRow["ID"]);
                                    auditRecord.TimeStamp     = Convert.ToDateTime(dataRow["TimeStamp"]);
                                    auditRecord.ArtifactId    = Convert.ToInt32(dataRow["ArtifactID"]);
                                    auditRecord.ActionId      = Convert.ToInt32(dataRow["ActionID"]);
                                    auditRecord.Action        = Convert.ToString(dataRow["Action"]);
                                    auditRecord.UserId        = Convert.ToInt32(dataRow["UserID"]);
                                    auditRecord.User          = Convert.ToString(dataRow["User"]);

                                    auditRecord.ExecutionTime = dataRow["ExecutionTime"] is DBNull ? default : Convert.ToInt32(dataRow["ExecutionTime"]);

                                                                auditRecord.Details = dataRow["Details"] is DBNull ? default : Convert.ToString(dataRow["Details"]);

                                                                                      auditRecord.RequestOrigination = dataRow["RequestOrigination"] is DBNull ? default : Convert.ToString(dataRow["RequestOrigination"]);

                                                                                                                       auditRecord.RecordOrigination = dataRow["RecordOrigination"] is DBNull ? default : Convert.ToString(dataRow["RecordOrigination"]);
                                                                                                                                                       auditRecords.Add(auditRecord);

                                                                                                                                                       // Record last Audit Log ID
                                                                                                                                                       if (newAuditRecordId < auditRecord.AuditRecordId)
                                                                                                                                                       {
                                                                                                                                                           newAuditRecordId = auditRecord.AuditRecordId;
                                                                                                                                                       }

                                                                                                                                                       // Index data in threshold is reached or we are at the last row
                                                                                                                                                       if (auditRecords.Count >= 500 || i + 1 >= dataTable.Rows.Count)
                                                                                                                                                       {
                                                                                                                                                           try
                                                                                                                                                           {
                                                                                                                                                               Nest.BulkResponse bulkResponse = elasticClient.Bulk(b => b.Index(elasticIndexName).IndexMany(auditRecords, (descriptor, s) => descriptor.Id(s.AuditRecordId.ToString())));
                                                                                                                                                               if (!bulkResponse.Errors)
                                                                                                                                                               {
                                                                                                                                                                   auditRecords.Clear();
                                                                                                                                                                   _logger.LogDebug("Audit Log Elastic Search, Agent ({agentArtifactId}), documents synchronized to Elastic Serach index ({indexName})", agentArtifactId.ToString(), elasticIndexName);
                                                                                                                                                               }
                                                                                                                                                               else
                                                                                                                                                               {
                                                                                                                                                                   this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                                                                                                                                                                   foreach (Nest.BulkResponseItemBase itemWithError in bulkResponse.ItemsWithErrors)
                                                                                                                                                                   {
                                                                                                                                                                       _logger.LogError("Audit Log Elastic Search, Agent ({agentArtifactId}), Elastic Serach bulk index error to index {indexName} ({elasticUris}) on document {docIs}:{docError}", agentArtifactId.ToString(), elasticIndexName, string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), itemWithError.Id, itemWithError.Error.ToString());
                                                                                                                                                                   }
                                                                                                                                                                   this.RaiseMessageNoLogging(string.Format("Elastic Serach bulk index error to index {0} ({1}).", elasticIndexName, string.Join(";", elasticUris.Select(x => x.ToString()).ToArray())), 1);
                                                                                                                                                                   return;
                                                                                                                                                               }
                                                                                                                                                           }
                                                                                                                                                           catch (Exception e)
                                                                                                                                                           {
                                                                                                                                                               this.releaseAgentLock(agentArtifactId, auditRecordId, workspaceId);
                                                                                                                                                               _logger.LogError(e, "Audit Log Elastic Search, Agent ({agentArtifactId}) Elastic Search bulk index call error ({elasticUris}, {indexName})", agentArtifactId.ToString(), string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName);
                                                                                                                                                               this.RaiseMessageNoLogging(string.Format("Elastic Search bulk index call error ({0}, {1}).", string.Join(";", elasticUris.Select(x => x.ToString()).ToArray()), elasticIndexName), 1);
                                                                                                                                                               return;
                                                                                                                                                           }
                                                                                                                                                       }
                                }

                                // After successful indexing assign new Audit Log ID
                                auditRecordId = newAuditRecordId;
                            }
                        }