Esempio n. 1
0
        public static void AfterTestRun()
        {
            try
            {
                if (_launchReporter != null)
                {
                    var request = new FinishLaunchRequest
                    {
                        EndTime = DateTime.UtcNow
                    };

                    var eventArg = new RunFinishedEventArgs(_service, request, _launchReporter);
                    ReportPortalAddin.OnBeforeRunFinished(null, eventArg);

                    if (!eventArg.Canceled)
                    {
                        _launchReporter.Finish(request);

                        var sw = Stopwatch.StartNew();

                        _traceLogger.Info($"Finishing to send results to ReportPortal...");
                        _launchReporter.Sync();
                        _traceLogger.Info($"Elapsed: {sw.Elapsed}");
                        _traceLogger.Info(_launchReporter.StatisticsCounter.ToString());

                        ReportPortalAddin.OnAfterRunFinished(null, new RunFinishedEventArgs(_service, request, _launchReporter));
                    }
                }
            }
            catch (Exception exp)
            {
                _traceLogger.Error(exp.ToString());
            }
        }
        public override Task <Empty> NotifyExecutionStarting(ExecutionStartingRequest request, ServerCallContext context)
        {
            try
            {
                TraceLogger.Info($"{nameof(NotifyExecutionStarting)} received");
                TraceLogger.Verbose(System.Text.Json.JsonSerializer.Serialize(request));

                if (request.SuiteResult != null)
                {
                    _sender.StartLaunch(request);
                }
            }
            catch (Exception exp)
            {
                TraceLogger.Error(exp.ToString());
            }

            return(Task.FromResult(new Empty()));
        }
 public override async Task <Empty> Kill(KillProcessRequest request, ServerCallContext context)
 {
     TraceLogger.Info("Kill received");
     try
     {
         return(new Empty());
     }
     finally
     {
         await _server.KillAsync();
     }
 }
        /// <summary>
        /// Detailed constructor where specified logger and telemetry data collector are initialized along with test run manager
        /// </summary>
        /// <param name="testRunPublisher"></param>
        /// <param name="diagnosticDataCollector"></param>
        /// <param name="telemetryDataCollector"></param>
        public JestTestResultParser(ITestRunManager testRunManager, ITraceLogger logger, ITelemetryDataCollector telemetryDataCollector)
            : base(testRunManager, logger, telemetryDataCollector)
        {
            logger.Info("JestTestResultParser : Starting jest test result parser.");
            telemetryDataCollector.AddToCumulativeTelemetry(JestTelemetryConstants.EventArea, JestTelemetryConstants.Initialize, true);

            // Initialize the starting state of the parser
            var testRun = new TestRun($"{Name}/{Version}", 1);

            this.stateContext = new JestParserStateContext(testRun);
            this.currentState = JestParserStates.ExpectingTestRunStart;
        }
        public override Task <Empty> Kill(KillProcessRequest request, ServerCallContext context)
        {
            TraceLogger.Info("Kill received");

            try
            {
                return(Task.FromResult(new Empty()));
            }
            finally
            {
                Program.ShutDownCancelationSource.Cancel();
            }
        }
        /// <summary>
        /// Detailed constructor where specified logger and telemetry data collector are initialized along with test run manager
        /// </summary>
        /// <param name="testRunPublisher"></param>
        /// <param name="diagnosticDataCollector"></param>
        /// <param name="telemetryDataCollector"></param>
        public MochaTestResultParser(ITestRunManager testRunManager, ITraceLogger logger, ITelemetryDataCollector telemetryDataCollector) : base(testRunManager, logger, telemetryDataCollector)
        {
            logger.Info("MochaTestResultParser : Starting mocha test result parser.");
            telemetryDataCollector.AddToCumulativeTelemetry(MochaTelemetryConstants.EventArea, MochaTelemetryConstants.Initialize, true);

            // Initialize the starting state of the parser
            var testRun = new TestRun($"{Name}/{Version}", 1);

            this.stateContext = new MochaParserStateContext(testRun);
            this.currentState = MochaParserStates.ExpectingTestResults;

            this.expectingTestResults    = new MochaExpectingTestResults(AttemptPublishAndResetParser, logger, telemetryDataCollector);
            this.expectingTestRunSummary = new MochaExpectingTestRunSummary(AttemptPublishAndResetParser, logger, telemetryDataCollector);
            this.expectingStackTraces    = new MochaExpectingStackTraces(AttemptPublishAndResetParser, logger, telemetryDataCollector);
        }
Esempio n. 7
0
        public Message GetMessage(string traceId, string messageId)
        {
            if (MessageCache.TryGetValue(messageId, out var msg))
            {
                return(msg);
            }

            var request = _service.Users.Messages.Get("me", messageId);

            request.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Full;

            var gMessage = request.Execute();

            List <Header> headers   = GetHeaders(gMessage.Payload).ToList();
            List <string> bodyParts = GetBody(gMessage.Payload).ToList();

            var message = new Message
            {
                Id      = gMessage.Id,
                Body    = string.Join(Environment.NewLine, bodyParts),
                Headers = headers
            };

            List <Tuple <string, string> > attachmentIds = GetAttachmentIds(gMessage.Payload).ToList();

            foreach (Tuple <string, string> attachmentId in attachmentIds)
            {
                try
                {
                    byte[] data = GetAttachment(messageId, attachmentId.Item1);
                    message.Attachments.Add(new Attachment
                    {
                        Id        = attachmentId.Item1,
                        Name      = attachmentId.Item2,
                        MessageId = messageId,
                        Data      = data
                    });
                }
                catch (Exception ex)
                {
                    _log.Info(traceId, "GetMessage.Attachment.Exception", $"id={attachmentId.Item1}, name={attachmentId.Item2}, msgId={message.Id}, exception=\"{ex.Message}\"");
                }
            }

            MessageCache.AddOrUpdate(messageId, message, (id, m) => message);
            return(message);
        }
Esempio n. 8
0
        /// <summary>
        /// Default implemenation that checks for the constraint for the next expected match
        /// If the number of lines within which the next match expected falls to 0 this resets the parser
        /// </summary>
        /// <param name="line">Current line</param>
        /// <param name="stateContext">State context object containing information of the parser's state</param>
        /// <returns>True if the parser was reset</returns>>
        public virtual bool PeformNoPatternMatchedAction(string line, AbstractParserStateContext stateContext)
        {
            // This is a mechanism to enforce matches that have to occur within
            // a specific number of lines after encountering the previous match
            // one obvious usage is for successive summary lines containing passed,
            // pending and failed test summary
            if (stateContext.LinesWithinWhichMatchIsExpected == 1)
            {
                Logger.Info($"{ParserName} : {StateName} : NoPatternMatched : Was expecting {stateContext.NextExpectedMatch} before line {stateContext.CurrentLineNumber}, but no matches occurred.");
                Telemetry.AddAndAggregate("UnexpectedParserResetCount", 1, ParserName);
                AttemptPublishAndResetParser();
                return(true);
            }

            // If no match occurred and a match was expected in a positive number of lines, decrement the counter
            // A value of zero or lesser indicates not expecting a match
            if (stateContext.LinesWithinWhichMatchIsExpected > 1)
            {
                stateContext.LinesWithinWhichMatchIsExpected--;
            }

            return(false);
        }
Esempio n. 9
0
        public async Task PublishAsync()
        {
            var testResultFiles = new List <string>();
            IList <TestRunData> testData;

            var testRunContext = new TestRunContextBuilder("JUnit test results")
                                 .WithBuildId(_pipelineConfig.BuildId)
                                 .WithBuildUri(_pipelineConfig.BuildUri)
                                 .WithStageName(_pipelineConfig.StageName)
                                 .WithStageAttempt(_pipelineConfig.StageAttempt)
                                 .WithPhaseName(_pipelineConfig.PhaseName)
                                 .WithPhaseAttempt(_pipelineConfig.PhaseAttempt)
                                 .WithJobName(_pipelineConfig.JobName)
                                 .WithJobAttempt(_pipelineConfig.JobAttempt)
                                 .Build();

            using (new SimpleTimer(TelemetryConstants.FindTestFilesAsync, _logger, TimeSpan.FromSeconds(60),
                                   new TelemetryDataWrapper(_telemetry, TelemetryConstants.FindTestFilesAsync)))
            {
                try
                {
                    testResultFiles.AddRange(await FindTestFilesAsync());

                    _logger.Info($"Number of files found with matching pattern {testResultFiles.Count}");
                }
                catch (Exception ex)
                {
                    _logger.Info($"Error: {ex.Message}");
                    _telemetry.AddOrUpdate("FindTestFilesError", ex);
                }
            }

            _telemetry.AddOrUpdate("NumberOfTestFilesFound", testResultFiles.Count);
            if (!testResultFiles.Any())
            {
                _logger.Info("No test result files are found");
                return;
            }

            using (new SimpleTimer(TelemetryConstants.ParseTestResultFiles, _logger, TimeSpan.FromSeconds(60),
                                   new TelemetryDataWrapper(_telemetry, TelemetryConstants.ParseTestResultFiles)))
            {
                testData = _testResultParser.ParseTestResultFiles(testRunContext, testResultFiles).GetTestRunData();

                _logger.Info($"Successfully parsed {testData?.Count} files");
                _telemetry.AddOrUpdate("NumberOfTestFilesRead", testData?.Count);
            }

            if (testData == null || !testData.Any())
            {
                _logger.Info("No valid Junit test result files are found which can be parsed");
                return;
            }

            using (new SimpleTimer(TelemetryConstants.PublishTestRunDataAsync, _logger, TimeSpan.FromSeconds(60),
                                   new TelemetryDataWrapper(_telemetry, TelemetryConstants.PublishTestRunDataAsync)))
            {
                var publishedRuns = await _testRunPublisher.PublishTestRunDataAsync(testRunContext, _pipelineConfig.ProjectName, testData, new PublishOptions(),
                                                                                    new CancellationToken());

                if (publishedRuns != null)
                {
                    _logger.Info($"Successfully published {publishedRuns.Count} runs");
                    _telemetry.AddOrUpdate("NumberOfTestRunsPublished", publishedRuns.Count);
                    _telemetry.AddOrUpdate("TestRunIds", string.Join(",", publishedRuns.Select(x => x.Id)));
                }
                else
                {
                    _telemetry.AddOrUpdate("NumberOfTestRunsPublished", 0);
                }
            }
        }
Esempio n. 10
0
 public override void Information(string message)
 {
     _log.Info("{0}", message);
 }
Esempio n. 11
0
        static async Task Main(string[] args)
        {
            var gaugeProjectRoot = Environment.GetEnvironmentVariable("GAUGE_PROJECT_ROOT");
            var gaugeLogsDir     = Environment.GetEnvironmentVariable("logs_directory");

            var internalTraceLogginDir = Path.Combine(gaugeProjectRoot, gaugeLogsDir);

            TraceLogger = TraceLogManager.Instance.WithBaseDir(internalTraceLogginDir).GetLogger <Program>();

            var envVariables = Environment.GetEnvironmentVariables();

            foreach (var envVariableKey in envVariables.Keys)
            {
                TraceLogger.Verbose($"{envVariableKey}: {envVariables[envVariableKey]}");
            }

            var configuration = new ConfigurationBuilder()
                                .Add(new EnvironmentVariablesConfigurationProvider("RP_", "_", EnvironmentVariableTarget.Process))
                                .Build();

            var rpUri            = configuration.GetValue <string>("Uri");
            var rpProject        = configuration.GetValue <string>("Project");
            var rpApiToken       = configuration.GetValue <string>("Uuid");
            var apiClientService = new Service(new Uri(rpUri), rpProject, rpApiToken);

            var sender = new Sender(apiClientService, configuration);

            var channelOptions = new List <ChannelOption> {
                new ChannelOption(ChannelOptions.MaxReceiveMessageLength, -1)
            };

            var server = new Server(channelOptions);

            ServerServiceDefinition messagesHandlerService;

            if (configuration.GetValue("Enabled", true))
            {
                messagesHandlerService = Reporter.BindService(new ReportMessagesHandler(server, sender));
            }
            else
            {
                messagesHandlerService = Reporter.BindService(new EmptyMessagesHandler(server));
            }
            server.Services.Add(messagesHandlerService);

            var gaugePort = server.Ports.Add(new ServerPort("localhost", 0, ServerCredentials.Insecure));

            server.Start();

            Console.Write($"Listening on port:{gaugePort}");

            TraceLogger.Info("Server has started.");

            await server.ShutdownTask;



            //var rpUri = new Uri(Config.GetValue<string>("Uri"));
            //var rpProject = Config.GetValue<string>("Project");
            //var rpUuid = Config.GetValue<string>("Uuid");

            //var service = new Service(rpUri, rpProject, rpUuid);
            //var launchReporter = new LaunchReporter(service, Config, null);

            //var tcpClientWrapper = new TcpClientWrapper(Gauge.CSharp.Core.Utils.GaugeApiPort);
            //using (var gaugeConnection = new GaugeConnection(tcpClientWrapper))
            //{
            //    while (gaugeConnection.Connected)
            //    {
            //        try
            //        {
            //            TraceLogger.Verbose($"Reading message...");

            //            var messageBytes = gaugeConnection.ReadBytes();
            //            TraceLogger.Verbose($"Read message. Length: {messageBytes.Count()}");

            //            var message = Message.Parser.ParseFrom(messageBytes.ToArray());
            //            TraceLogger.Verbose($"Received event {message.MessageType}");

            //            //if (message.MessageType == Message.Types.MessageType.SuiteExecutionResult)
            //            //{
            //            //    var suiteExecutionResult = message.SuiteExecutionResult.SuiteResult;

            //            //    var launchStartDateTime = DateTime.UtcNow.AddMilliseconds(-suiteExecutionResult.ExecutionTime);
            //            //    launchReporter.Start(new Client.Requests.StartLaunchRequest
            //            //    {
            //            //        Name = Config.GetValue("Launch:Name", suiteExecutionResult.ProjectName),
            //            //        Description = Config.GetValue("Launch:Description", string.Empty),
            //            //        Tags = Config.GetValues("Launch:Tags", new List<string>()).ToList(),
            //            //        StartTime = launchStartDateTime
            //            //    });

            //            //    foreach (var specResult in suiteExecutionResult.SpecResults)
            //            //    {
            //            //        var specStartTime = launchStartDateTime;
            //            //        var specReporter = launchReporter.StartChildTestReporter(new Client.Requests.StartTestItemRequest
            //            //        {
            //            //            Type = Client.Models.TestItemType.Suite,
            //            //            Name = specResult.ProtoSpec.SpecHeading,
            //            //            Description = string.Join("", specResult.ProtoSpec.Items.Where(i => i.ItemType == ProtoItem.Types.ItemType.Comment).Select(c => c.Comment.Text)),
            //            //            StartTime = specStartTime,
            //            //            Tags = specResult.ProtoSpec.Tags.Select(t => t.ToString()).ToList()
            //            //        });

            //            //        foreach (var scenarioResult in specResult.ProtoSpec.Items.Where(i => i.ItemType == ProtoItem.Types.ItemType.Scenario || i.ItemType == ProtoItem.Types.ItemType.TableDrivenScenario))
            //            //        {
            //            //            ProtoScenario scenario;

            //            //            switch (scenarioResult.ItemType)
            //            //            {
            //            //                case ProtoItem.Types.ItemType.Scenario:
            //            //                    scenario = scenarioResult.Scenario;
            //            //                    break;
            //            //                case ProtoItem.Types.ItemType.TableDrivenScenario:
            //            //                    scenario = scenarioResult.TableDrivenScenario.Scenario;
            //            //                    break;
            //            //                default:
            //            //                    scenario = scenarioResult.Scenario;
            //            //                    break;
            //            //            }

            //            //            var scenarioStartTime = specStartTime;
            //            //            var scenarioReporter = specReporter.StartChildTestReporter(new Client.Requests.StartTestItemRequest
            //            //            {
            //            //                Type = Client.Models.TestItemType.Step,
            //            //                StartTime = scenarioStartTime,
            //            //                Name = scenario.ScenarioHeading,
            //            //                Description = string.Join("", scenario.ScenarioItems.Where(i => i.ItemType == ProtoItem.Types.ItemType.Comment).Select(c => c.Comment.Text)),
            //            //                Tags = scenario.Tags.Select(t => t.ToString()).ToList()
            //            //            });

            //            //            // internal log ("rp_log_enabled" property)
            //            //            if (Config.GetValue("log:enabled", false))
            //            //            {
            //            //                scenarioReporter.Log(new Client.Requests.AddLogItemRequest
            //            //                {
            //            //                    Text = "Spec Result Proto",
            //            //                    Level = Client.Models.LogLevel.Trace,
            //            //                    Time = DateTime.UtcNow,
            //            //                    Attach = new Client.Models.Attach("Spec", "application/json", System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(specResult)))
            //            //                });
            //            //                scenarioReporter.Log(new Client.Requests.AddLogItemRequest
            //            //                {
            //            //                    Text = "Scenario Result Proto",
            //            //                    Level = Client.Models.LogLevel.Trace,
            //            //                    Time = DateTime.UtcNow,
            //            //                    Attach = new Client.Models.Attach("Scenario", "application/json", System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(scenarioResult)))
            //            //                });
            //            //            }

            //            //            var lastStepStartTime = scenarioStartTime;
            //            //            if (scenario.ScenarioItems != null)
            //            //            {
            //            //                foreach (var stepResult in scenario.ScenarioItems.Where(i => i.ItemType == ProtoItem.Types.ItemType.Step))
            //            //                {
            //            //                    var text = "!!!MARKDOWN_MODE!!!" + stepResult.Step.ActualText;
            //            //                    var stepLogLevel = stepResult.Step.StepExecutionResult.ExecutionResult.Failed ? Client.Models.LogLevel.Error : Client.Models.LogLevel.Info;

            //            //                    // if step argument is table
            //            //                    var tableParameter = stepResult.Step.Fragments.FirstOrDefault(f => f.Parameter?.Table != null)?.Parameter.Table;
            //            //                    if (tableParameter != null)
            //            //                    {
            //            //                        text += Environment.NewLine + Environment.NewLine + "| " + string.Join(" | ", tableParameter.Headers.Cells.ToArray()) + " |";
            //            //                        text += Environment.NewLine + "| " + string.Join(" | ", tableParameter.Headers.Cells.Select(c => "---")) + " |";

            //            //                        foreach (var tableRow in tableParameter.Rows)
            //            //                        {
            //            //                            text += Environment.NewLine + "| " + string.Join(" | ", tableRow.Cells.ToArray()) + " |";
            //            //                        }
            //            //                    }

            //            //                    // if dynamic arguments
            //            //                    var dynamicParameteres = stepResult.Step.Fragments.Where(f => f.FragmentType == Fragment.Types.FragmentType.Parameter && f.Parameter.ParameterType == Parameter.Types.ParameterType.Dynamic).Select(f => f.Parameter);
            //            //                    if (dynamicParameteres.Count() != 0)
            //            //                    {
            //            //                        text += Environment.NewLine;

            //            //                        foreach (var dynamicParameter in dynamicParameteres)
            //            //                        {
            //            //                            text += $"{Environment.NewLine}{dynamicParameter.Name}: {dynamicParameter.Value}";
            //            //                        }
            //            //                    }

            //            //                    if (stepResult.Step.StepExecutionResult.ExecutionResult.Failed)
            //            //                    {
            //            //                        text += $"{Environment.NewLine}{Environment.NewLine}{stepResult.Step.StepExecutionResult.ExecutionResult.ErrorMessage}{Environment.NewLine}{stepResult.Step.StepExecutionResult.ExecutionResult.StackTrace}";
            //            //                    }

            //            //                    scenarioReporter.Log(new Client.Requests.AddLogItemRequest
            //            //                    {
            //            //                        Level = stepLogLevel,
            //            //                        Time = lastStepStartTime,
            //            //                        Text = text
            //            //                    });

            //            //                    if (stepResult.Step.StepExecutionResult.ExecutionResult.ScreenShot?.Length != 0)
            //            //                    {
            //            //                        scenarioReporter.Log(new Client.Requests.AddLogItemRequest
            //            //                        {
            //            //                            Level = Client.Models.LogLevel.Debug,
            //            //                            Time = lastStepStartTime,
            //            //                            Text = "Screenshot",
            //            //                            Attach = new Client.Models.Attach("Screenshot", "image/png", stepResult.Step.StepExecutionResult.ExecutionResult.ScreenShot.ToByteArray())
            //            //                        });
            //            //                    }

            //            //                    lastStepStartTime = lastStepStartTime.AddMilliseconds(stepResult.Step.StepExecutionResult.ExecutionResult.ExecutionTime);
            //            //                }
            //            //            }

            //            //            scenarioReporter.Finish(new Client.Requests.FinishTestItemRequest
            //            //            {
            //            //                EndTime = scenarioStartTime.AddMilliseconds(scenario.ExecutionTime),
            //            //                Status = _statusMap[scenario.ExecutionStatus]
            //            //            });
            //            //        }

            //            //        var specFinishStatus = specResult.Failed ? Client.Models.Status.Failed : Client.Models.Status.Passed;
            //            //        specReporter.Finish(new Client.Requests.FinishTestItemRequest
            //            //        {
            //            //            Status = specFinishStatus,
            //            //            EndTime = specStartTime.AddMilliseconds(specResult.ExecutionTime)
            //            //        });
            //            //    }

            //            //    launchReporter.Finish(new Client.Requests.FinishLaunchRequest
            //            //    {
            //            //        EndTime = DateTime.UtcNow
            //            //    });
            //            //}

            //            if (message.MessageType == Message.Types.MessageType.KillProcessRequest)
            //            {
            //                Console.Write("Finishing to send results to Report Portal... ");
            //                var sw = Stopwatch.StartNew();
            //                launchReporter.Sync();

            //                Console.WriteLine($"Elapsed: {sw.Elapsed}");

            //                return;
            //            }
            //        }
            //        catch (Exception exp)
            //        {
            //            TraceLogger.Error($"Unhandler error: {exp}");
            //        }
            //    }
            //}
        }
Esempio n. 12
0
        public void FormatLog(CreateLogItemRequest logRequest)
        {
            _traceLogger.Verbose("Received a log request to format.");

            var handled = false;

            var fullMessageBuilder = Config.GetValue("Extensions:SourceBack:WithMarkdownPrefix", false) ? new StringBuilder("!!!MARKDOWN_MODE!!!") : new StringBuilder();

            if (logRequest.Level == LogLevel.Error || logRequest.Level == LogLevel.Fatal)
            {
                _traceLogger.Info($"Parsing exception stacktrace in log message with {logRequest.Level} level...");

                foreach (var line in logRequest.Text.Split(new string[] { Environment.NewLine, "\n" }, StringSplitOptions.None))
                {
                    _traceLogger.Verbose("Parsing line as stacktrace frame:" + Environment.NewLine + line);

                    var lineWithoutMarkdown = line.Replace("`", @"\`").Replace("__", @"\__");

                    var match = Regex.Match(line, @"\s+\w+\s.*\s\w+\s(.*):\w+\s(\d+)");

                    if (match.Success)
                    {
                        var sourcePath = match.Groups[1].Value;
                        var lineIndex  = int.Parse(match.Groups[2].Value) - 1;

                        _traceLogger.Info($"It matches stacktrace. SourcePath: {sourcePath} - LineIndex: {lineIndex}");

                        var sectionBuilder = new StringBuilder();

                        try
                        {
                            lock (_pdbsLock)
                            {
                                if (_pdbs == null)
                                {
                                    _pdbs = new List <PdbFileInfo>();

                                    var currentDirectory = new DirectoryInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName;

                                    _traceLogger.Verbose($"Exploring {currentDirectory} directory for PDB files");

                                    var pdbFilePaths = DirectoryScanner.FindPdbPaths(currentDirectory);

                                    foreach (var pdbFilePath in pdbFilePaths)
                                    {
                                        var pdbFileInfo = new PdbFileInfo(pdbFilePath);

                                        try
                                        {
                                            pdbFileInfo.LoadSourceLinks();
                                        }
                                        catch (NotSupportedException exp)
                                        {
                                            _traceLogger.Warn($"{pdbFilePath} format is not supported. Try to change it to 'portable' or 'embedded'. {Environment.NewLine}{exp}");
                                        }

                                        _pdbs.Add(pdbFileInfo);
                                    }
                                }
                            }

                            var pdb = _pdbs.FirstOrDefault(p => p.SourceLinks.ContainsKey(sourcePath));

                            // if defined
                            if (pdb != null)
                            {
                                var content = pdb.GetSourceLinkContent(sourcePath);

                                // if available
                                if (content != null)
                                {
                                    var contentLines = content.Replace("\r\n", "\n").Split(new string[] { "\n" }, StringSplitOptions.None);

                                    // up
                                    var offsetUp             = Config.GetValue("Extensions:SourceBack:OffsetUp", 4);
                                    var takeFromIndex        = lineIndex - offsetUp;
                                    var missingTopLinesCount = 0;
                                    if (takeFromIndex < 0)
                                    {
                                        missingTopLinesCount = Math.Abs(takeFromIndex);
                                        takeFromIndex        = 0;
                                    }

                                    // down
                                    var offsetDown  = Config.GetValue("Extensions:SourceBack:OffsetDown", 2);
                                    var takeToIndex = lineIndex + offsetDown;
                                    if (takeToIndex > contentLines.Length - 1)
                                    {
                                        takeToIndex = contentLines.Length - 1;
                                    }

                                    // and add whitespace to replace it with ►
                                    var frameContentLines = contentLines.Skip(takeFromIndex + 1).Take(takeToIndex - takeFromIndex).Select(l => " " + l).ToList();

                                    var hightlightFrameLineIndex = offsetUp - missingTopLinesCount - 1;
                                    frameContentLines[hightlightFrameLineIndex] = "►" + frameContentLines[hightlightFrameLineIndex].Remove(0, 1);
                                    var frameContent = string.Join(Environment.NewLine, frameContentLines);

                                    sectionBuilder.AppendLine($"```{Environment.NewLine}{frameContent}{Environment.NewLine}```");
                                }
                            }
                        }
                        catch (Exception exp)
                        {
                            sectionBuilder.AppendLine($"```{Environment.NewLine}SourceBack error: {exp}{Environment.NewLine}```");
                        }

                        handled = true;

                        if (!string.IsNullOrEmpty(sectionBuilder.ToString()))
                        {
                            var sourceFileName   = Path.GetFileName(sourcePath);
                            var lineWithEditLink = lineWithoutMarkdown.Replace("\\" + sourceFileName, $"\\\\**{sourceFileName}**");
                            lineWithEditLink = lineWithEditLink.Remove(lineWithEditLink.Length - match.Groups[2].Value.Length);

                            var openWith = Config.GetValue("Extensions:SourceBack:OpenWith", "vscode");
                            switch (openWith.ToLowerInvariant())
                            {
                            case "vscode":
                                lineWithEditLink += $"[{match.Groups[2].Value}](vscode://file/{sourcePath.Replace("\\", "/")}:{lineIndex + 1})";
                                break;
                            }

                            fullMessageBuilder.AppendLine($"{lineWithEditLink}{Environment.NewLine}{sectionBuilder}");
                        }
                        else
                        {
                            fullMessageBuilder.AppendLine(lineWithoutMarkdown);
                        }
                    }
                    else
                    {
                        fullMessageBuilder.AppendLine(lineWithoutMarkdown);
                    }
                }
            }

            if (handled)
            {
                logRequest.Text = fullMessageBuilder.ToString();
            }
        }