Commit 09c4b994 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '35411-syntax-highlight-for-sentry-stacktrace' into 'master'

Add syntax highlight for Senty error stack trace

See merge request gitlab-org/gitlab!21182
parents d94fc2c6 6aafca2d
......@@ -77,8 +77,10 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
return if handle_errors(result)
result_with_syntax_highlight = Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(result[:latest_event])
render json: {
error: serialize_error_event(result[:latest_event])
error: serialize_error_event(result_with_syntax_highlight)
}
end
......
---
title: Add syntax highlight for Sentry error stack trace
merge_request: 21182
author:
type: added
# frozen_string_literal: true
module Gitlab
module ErrorTracking
module StackTraceHighlightDecorator
extend self
def decorate(error_event)
::Gitlab::ErrorTracking::ErrorEvent.new(
issue_id: error_event.issue_id,
date_received: error_event.date_received,
stack_trace_entries: highlight_stack_trace(error_event.stack_trace_entries)
)
end
private
def highlight_stack_trace(stack_trace)
stack_trace.map do |entry|
highlight_stack_trace_entry(entry)
end
end
def highlight_stack_trace_entry(entry)
return entry unless entry['context']
entry.merge('context' => highlight_entry_context(entry['filename'], entry['context']))
end
def highlight_entry_context(filename, context)
language = Rouge::Lexer.guess_by_filename(filename).tag
context.map do |line_number, line_of_code|
[
line_number,
# Passing nil for the blob name allows skipping linking dependencies for the line_of_code
Gitlab::Highlight.highlight(nil, line_of_code, language: language)
]
end
end
end
end
end
......@@ -384,6 +384,10 @@ describe Projects::ErrorTrackingController do
).permit!
end
subject(:get_stack_trace) do
get :stack_trace, params: issue_params(issue_id: issue_id, format: :json)
end
before do
expect(ErrorTracking::IssueLatestEventService)
.to receive(:new).with(project, user, permitted_params)
......@@ -398,7 +402,7 @@ describe Projects::ErrorTrackingController do
end
it 'returns no data' do
get :stack_trace, params: issue_params(issue_id: issue_id, format: :json)
get_stack_trace
expect(response).to have_gitlab_http_status(:no_content)
end
......@@ -408,16 +412,21 @@ describe Projects::ErrorTrackingController do
before do
expect(issue_stack_trace_service).to receive(:execute)
.and_return(status: :success, latest_event: error_event)
get_stack_trace
end
let(:error_event) { build(:error_tracking_error_event) }
it 'returns an error' do
get :stack_trace, params: issue_params(issue_id: issue_id, format: :json)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('error_tracking/issue_stack_trace')
expect(json_response['error']).to eq(error_event.as_json)
end
it 'highlights stack trace source code' do
expect(json_response['error']).to eq(
Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(error_event).as_json
)
end
end
......@@ -431,7 +440,7 @@ describe Projects::ErrorTrackingController do
end
it 'returns 400 with message' do
get :stack_trace, params: issue_params(issue_id: issue_id, format: :json)
get_stack_trace
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq(error_message)
......@@ -450,7 +459,7 @@ describe Projects::ErrorTrackingController do
end
it 'returns http_status with message' do
get :stack_trace, params: issue_params(issue_id: issue_id, format: :json)
get_stack_trace
expect(response).to have_gitlab_http_status(http_status)
expect(json_response['message']).to eq(error_message)
......
......@@ -5,12 +5,40 @@ FactoryBot.define do
issue_id { 'id' }
date_received { Time.now.iso8601 }
stack_trace_entries do
{
'stacktrace' =>
{
'frames' => [{ 'file' => 'test.rb' }]
}
}
[
{
'function' => 'puts',
'lineNo' => 14,
'filename' => 'hello_world.rb',
'context' => [
[10, "# Ruby example\n"],
[11, "class HelloWorld\n"],
[12, " def self.message\n"],
[13, " @name = 'World'\n"],
[14, " puts \"Hello \#{@name}\"\n"],
[15, " end\n"],
[16, "end\n"]
]
},
{
'function' => 'print',
'lineNo' => 6,
'filename' => 'HelloWorld.swift',
'context' => [
[1, "// Swift example\n"],
[2, "struct HelloWorld {\n"],
[3, " let name = \"World\"\n"],
[4, "\n"],
[5, " static func message() {\n"],
[6, " print(\"Hello, \\(self.name)\")\n"],
[7, " }\n"],
[8, "}\n"]
]
},
{
'filename' => 'blank.txt'
}
]
end
skip_create
......
......@@ -7,7 +7,7 @@
],
"properties": {
"issue_id": { "type": ["string", "integer"] },
"stack_trace_entries": { "type": "object" },
"stack_trace_entries": { "type": "array" },
"date_received": { "type": "string" }
},
"additionalProperties": false
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::ErrorTracking::StackTraceHighlightDecorator do
let(:error_event) { build(:error_tracking_error_event) }
describe '.decorate' do
subject(:decorate) { described_class.decorate(error_event) }
it 'does not change issue_id' do
expect(decorate.issue_id).to eq(error_event.issue_id)
end
it 'does not change date_received' do
expect(decorate.date_received).to eq(error_event.date_received)
end
it 'decorates the stack trace context' do
expect(decorate.stack_trace_entries).to eq(
[
{
'function' => 'puts',
'lineNo' => 14,
'filename' => 'hello_world.rb',
'context' => [
[10, '<span id="LC1" class="line" lang="ruby"><span class="c1"># Ruby example</span></span>'],
[11, '<span id="LC1" class="line" lang="ruby"><span class="k">class</span> <span class="nc">HelloWorld</span></span>'],
[12, '<span id="LC1" class="line" lang="ruby"> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">message</span></span>'],
[13, '<span id="LC1" class="line" lang="ruby"> <span class="vi">@name</span> <span class="o">=</span> <span class="s1">\'World\'</span></span>'],
[14, %Q[<span id="LC1" class="line" lang="ruby"> <span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">\#{</span><span class="vi">@name</span><span class="si">}</span><span class="s2">"</span></span>]],
[15, '<span id="LC1" class="line" lang="ruby"> <span class="k">end</span></span>'],
[16, '<span id="LC1" class="line" lang="ruby"><span class="k">end</span></span>']
]
},
{
'function' => 'print',
'lineNo' => 6,
'filename' => 'HelloWorld.swift',
'context' => [
[1, '<span id="LC1" class="line" lang="swift"><span class="c1">// Swift example</span></span>'],
[2, '<span id="LC1" class="line" lang="swift"><span class="kd">struct</span> <span class="kt">HelloWorld</span> <span class="p">{</span></span>'],
[3, '<span id="LC1" class="line" lang="swift"> <span class="k">let</span> <span class="nv">name</span> <span class="o">=</span> <span class="s">"World"</span></span>'],
[4, '<span id="LC1" class="line" lang="swift"></span>'],
[5, '<span id="LC1" class="line" lang="swift"> <span class="kd">static</span> <span class="kd">func</span> <span class="nf">message</span><span class="p">()</span> <span class="p">{</span></span>'],
[6, '<span id="LC1" class="line" lang="swift"> <span class="nf">print</span><span class="p">(</span><span class="s">"Hello, </span><span class="se">\\(</span><span class="k">self</span><span class="o">.</span><span class="n">name</span><span class="se">)</span><span class="s">"</span><span class="p">)</span></span>'],
[7, '<span id="LC1" class="line" lang="swift"> <span class="p">}</span></span>'],
[8, '<span id="LC1" class="line" lang="swift"><span class="p">}</span></span>']
]
},
{
'filename' => 'blank.txt'
}
]
)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment