Skip to content

Add Error tracking models

Dmytro Zaporozhets (DZ) requested to merge dz-error-tracking-backend-models into master

What does this MR do?

This MR is first in series to implement error tracking functionality inside GitLab. Issue #329596 (closed).

This MR introduces 2 models:

  1. ErrorTracking::Error - to store errors.
  2. ErrorTracking::ErrorEvent - to store each event when the error is occured.

Every time the error is raised in client application, we will receive a request with error event information. We will insert 1 row of ErrorTracking::ErrorEvent and insert or update 1 row of ErrorTracking::Error.

From a user perspective

User will browse a list of Error in the project. Based on first_seen_at, last_seen_at and count of ErrorEvent per Error a user can decide on fixing the error. The payload from ErrorEvent provides a stacktrace and other important information to locate the source and the cause of error.

Migrations

UP

Click to expand
== 20210623133635 CreateErrorTrackingErrors: migrating ========================
-- create_table(:error_tracking_errors, {})
-- quote_column_name(:name)
   -> 0.0000s
-- quote_column_name(:description)
   -> 0.0000s
-- quote_column_name(:actor)
   -> 0.0000s
-- quote_column_name(:platform)
   -> 0.0000s
   -> 0.0077s
-- quote_table_name("check_18a758e537")
   -> 0.0000s
-- quote_table_name("check_c739788b12")
   -> 0.0000s
-- quote_table_name("check_b5cb4d3888")
   -> 0.0000s
-- quote_table_name("check_fe99886883")
   -> 0.0000s
-- quote_table_name(:error_tracking_errors)
   -> 0.0000s
-- execute("ALTER TABLE \"error_tracking_errors\"\nADD CONSTRAINT \"check_18a758e537\" CHECK (char_length(\"name\") <= 255),\nADD CONSTRAINT \"check_c739788b12\" CHECK (char_length(\"description\") <= 1024),\nADD CONSTRAINT \"check_b5cb4d3888\" CHECK (char_length(\"actor\") <= 255),\nADD CONSTRAINT \"check_fe99886883\" CHECK (char_length(\"platform\") <= 255)\n")
   -> 0.0009s
== 20210623133635 CreateErrorTrackingErrors: migrated (0.0128s) ===============

== 20210625094554 CreateErrorTrackingErrorEvents: migrating ===================
-- create_table(:error_tracking_error_events, {})
-- quote_column_name(:description)
   -> 0.0000s
-- quote_column_name(:environment)
   -> 0.0000s
-- quote_column_name(:level)
   -> 0.0000s
   -> 0.0042s
-- quote_table_name("check_92ecc3077b")
   -> 0.0000s
-- quote_table_name("check_f4b52474ad")
   -> 0.0000s
-- quote_table_name("check_c67d5b8007")
   -> 0.0000s
-- quote_table_name(:error_tracking_error_events)
   -> 0.0000s
-- execute("ALTER TABLE \"error_tracking_error_events\"\nADD CONSTRAINT \"check_92ecc3077b\" CHECK (char_length(\"description\") <= 255),\nADD CONSTRAINT \"check_f4b52474ad\" CHECK (char_length(\"environment\") <= 255),\nADD CONSTRAINT \"check_c67d5b8007\" CHECK (char_length(\"level\") <= 255)\n")
   -> 0.0007s
== 20210625094554 CreateErrorTrackingErrorEvents: migrated (0.0078s) ==========

Down

Click to expand
== 20210625094554 CreateErrorTrackingErrorEvents: reverting ===================
-- drop_table(:error_tracking_error_events)
   -> 0.0022s
== 20210625094554 CreateErrorTrackingErrorEvents: reverted (0.0023s) ==========

== 20210623133635 CreateErrorTrackingErrors: reverting ========================
-- drop_table(:error_tracking_errors)
   -> 0.0025s
== 20210623133635 CreateErrorTrackingErrors: reverted (0.0026s) ===============

Data sample

Example of data that will be stored in JSONB payload. Current expected size is in 10...40KB range. The majority of data is in stacktrace object. We can truncate some data there if necessary. Or even extract stacktrace into separate Rails model.

Click to expand
{
   "event_id":"85e5e06034a24090bb2d1cfd7a4cba86",
   "level":"error",
   "timestamp":"2021-06-23T10:25:00Z",
   "release":"ad10ffb",
   "environment":"development",
   "server_name":"dz-laptop.local",
   "message":"",
   "tags":{
      "request_id":"a7dec25c-988d-4f71-8640-afd07db549f1"
   },
   "contexts":{
      "os":{
         "name":"Darwin",
         "version":"Darwin Kernel Version 20.5.0: Sat May  8 05:10:33 PDT 2021; root:xnu-7195.121.3~9/RELEASE_X86_64",
         "build":"20.5.0",
         "kernel_version":"Darwin Kernel Version 20.5.0: Sat May  8 05:10:33 PDT 2021; root:xnu-7195.121.3~9/RELEASE_X86_64"
      },
      "runtime":{
         "name":"ruby",
         "version":"ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin19]"
      },
      "trace":{
         "trace_id":"34db6833ee8f4e178d076c2b6ac56229",
         "span_id":"c4f70f111e78a9bb",
         "parent_span_id":null,
         "description":null,
         "op":"rails.request",
         "status":null
      }
   },
   "breadcrumbs":{
      "values":[
         {
            "category":"start_processing.action_controller",
            "data":{
               "controller":"PostsController",
               "action":"error2",
               "params":{
                  "controller":"posts",
                  "action":"error2"
               },
               "format":"html",
               "method":"GET",
               "path":"/posts/error2",
               "start_timestamp":1624443900.243959
            },
            "level":null,
            "message":"",
            "timestamp":1624443900,
            "type":null
         },
         {
            "category":"process_action.action_controller",
            "data":{
               "controller":"PostsController",
               "action":"error2",
               "params":{
                  "controller":"posts",
                  "action":"error2"
               },
               "format":"html",
               "method":"GET",
               "path":"/posts/error2",
               "start_timestamp":1624443900.2440488,
               "view_runtime":null,
               "db_runtime":0
            },
            "level":null,
            "message":"",
            "timestamp":1624443900,
            "type":null
         }
      ]
   },
   "transaction":"PostsController#error2",
   "platform":"ruby",
   "sdk":{
      "name":"sentry.ruby.rails",
      "version":"4.5.1"
   },
   "request":{
      "url":"http://localhost:4444/posts/error2",
      "method":"GET",
      "headers":{
         "Host":"localhost:4444",
         "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0",
         "Accept":"text/html, application/xhtml+xml",
         "Accept-Language":"en-US,en;q=0.5",
         "Accept-Encoding":"gzip, deflate",
         "Referer":"http://localhost:4444/",
         "Turbolinks-Referrer":"http://localhost:4444/",
         "Connection":"keep-alive"
      },
      "env":{
         "SERVER_NAME":"localhost",
         "SERVER_PORT":"4444"
      }
   },
   "exception":{
      "values":[
         {
            "type":"ActionView::MissingTemplate",
            "value":"Missing template posts/error2, application/error2 with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:\n  * \"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth/app/views\"\n",
            "module":"ActionView",
            "thread_id":70292510053520,
            "stacktrace":{
               "frames":[
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/thread_pool.rb",
                     "function":"block in spawn_thread",
                     "lineno":135,
                     "in_app":false,
                     "filename":"puma/thread_pool.rb",
                     "pre_context":[
                        "          end\n",
                        "\n",
                        "          begin\n"
                     ],
                     "context_line":"            block.call(work, *extra)\n",
                     "post_context":[
                        "          rescue Exception => e\n",
                        "            STDERR.puts \"Error reached top of thread-pool: #{e.message} (#{e.class})\"\n",
                        "          end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb",
                     "function":"block in run",
                     "lineno":334,
                     "in_app":false,
                     "filename":"puma/server.rb",
                     "pre_context":[
                        "          client.close\n",
                        "        else\n",
                        "          if process_now\n"
                     ],
                     "context_line":"            process_client client, buffer\n",
                     "post_context":[
                        "          else\n",
                        "            client.set_timeout @first_data_timeout\n",
                        "            @reactor.add client\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb",
                     "function":"process_client",
                     "lineno":476,
                     "in_app":false,
                     "filename":"puma/server.rb",
                     "pre_context":[
                        "        requests = 0\n",
                        "\n",
                        "        while true\n"
                     ],
                     "context_line":"          case handle_request(client, buffer)\n",
                     "post_context":[
                        "          when false\n",
                        "            return\n",
                        "          when :async\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb",
                     "function":"handle_request",
                     "lineno":706,
                     "in_app":false,
                     "filename":"puma/server.rb",
                     "pre_context":[
                        "\n",
                        "      begin\n",
                        "        begin\n"
                     ],
                     "context_line":"          status, headers, res_body = @app.call(env)\n",
                     "post_context":[
                        "\n",
                        "          return :async if req.hijacked\n",
                        "\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/configuration.rb",
                     "function":"call",
                     "lineno":227,
                     "in_app":false,
                     "filename":"puma/configuration.rb",
                     "pre_context":[
                        "\n",
                        "      def call(env)\n",
                        "        env[Const::PUMA_CONFIG] = @config\n"
                     ],
                     "context_line":"        @app.call(env)\n",
                     "post_context":[
                        "      end\n",
                        "    end\n",
                        "\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.6/lib/rails/engine.rb",
                     "function":"call",
                     "lineno":524,
                     "in_app":false,
                     "filename":"rails/engine.rb",
                     "pre_context":[
                        "    # Define the Rack API for this engine.\n",
                        "    def call(env)\n",
                        "      req = build_request env\n"
                     ],
                     "context_line":"      app.call req.env\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    # Defines additional Rack env configuration that is added on each call.\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.3/lib/rack/sendfile.rb",
                     "function":"call",
                     "lineno":110,
                     "in_app":false,
                     "filename":"rack/sendfile.rb",
                     "pre_context":[
                        "    end\n",
                        "\n",
                        "    def call(env)\n"
                     ],
                     "context_line":"      status, headers, body = @app.call(env)\n",
                     "post_context":[
                        "      if body.respond_to?(:to_path)\n",
                        "        case type = variation(env)\n",
                        "        when 'X-Accel-Redirect'\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_dispatch/middleware/static.rb",
                     "function":"call",
                     "lineno":127,
                     "in_app":false,
                     "filename":"action_dispatch/middleware/static.rb",
                     "pre_context":[
                        "        end\n",
                        "      end\n",
                        "\n"
                     ],
                     "context_line":"      @app.call(req.env)\n",
                     "post_context":[
                        "    end\n",
                        "  end\n",
                        "end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_dispatch/middleware/executor.rb",
                     "function":"call",
                     "lineno":14,
                     "in_app":false,
                     "filename":"action_dispatch/middleware/executor.rb",
                     "pre_context":[
                        "    def call(env)\n",
                        "      state = @executor.run!\n",
                        "      begin\n"
                     ],
                     "context_line":"        response = @app.call(env)\n",
                     "post_context":[
                        "        returned = response << ::Rack::BodyProxy.new(response.pop) { state.complete! }\n",
                        "      ensure\n",
                        "        state.complete! unless returned\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/sentry-ruby-core-4.5.1/lib/sentry/rack/capture_exceptions.rb",
                     "function":"call",
                     "lineno":14,
                     "in_app":false,
                     "filename":"sentry/rack/capture_exceptions.rb",
                     "pre_context":[
                        "        # make sure the current thread has a clean hub\n",
                        "        Sentry.clone_hub_to_current_thread\n",
                        "\n"
                     ],
                     "context_line":"        Sentry.with_scope do |scope|\n",
                     "post_context":[
                        "          scope.clear_breadcrumbs\n",
                        "          scope.set_transaction_name(env[\"PATH_INFO\"]) if env[\"PATH_INFO\"]\n",
                        "          scope.set_rack_env(env)\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/sentry-ruby-core-4.5.1/lib/sentry-ruby.rb",
                     "function":"with_scope",
                     "lineno":167,
                     "in_app":false,
                     "filename":"sentry-ruby.rb",
                     "pre_context":[
                        "    # ```\n",
                        "    #\n",
                        "    def with_scope(&block)\n"
                     ],
                     "context_line":"      get_current_hub&.with_scope(&block)\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    # Takes an exception and reports it to Sentry via the currently active hub.\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/sentry-ruby-core-4.5.1/lib/sentry/hub.rb",
                     "function":"with_scope",
                     "lineno":56,
                     "in_app":false,
                     "filename":"sentry/hub.rb",
                     "pre_context":[
                        "\n",
                        "    def with_scope(&block)\n",
                        "      push_scope\n"
                     ],
                     "context_line":"      yield(current_scope)\n",
                     "post_context":[
                        "    ensure\n",
                        "      pop_scope\n",
                        "    end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/sentry-ruby-core-4.5.1/lib/sentry/rack/capture_exceptions.rb",
                     "function":"block in call",
                     "lineno":23,
                     "in_app":false,
                     "filename":"sentry/rack/capture_exceptions.rb",
                     "pre_context":[
                        "          scope.set_span(transaction) if transaction\n",
                        "\n",
                        "          begin\n"
                     ],
                     "context_line":"            response = @app.call(env)\n",
                     "post_context":[
                        "          rescue Sentry::Error\n",
                        "            finish_transaction(transaction, 500)\n",
                        "            raise # Don't capture Sentry errors\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/cache/strategy/local_cache_middleware.rb",
                     "function":"call",
                     "lineno":29,
                     "in_app":false,
                     "filename":"active_support/cache/strategy/local_cache_middleware.rb",
                     "pre_context":[
                        "\n",
                        "          def call(env)\n",
                        "            LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)\n"
                     ],
                     "context_line":"            response = @app.call(env)\n",
                     "post_context":[
                        "            response[2] = ::Rack::BodyProxy.new(response[2]) do\n",
                        "              LocalCacheRegistry.set_cache_for(local_cache_key, nil)\n",
                        "            end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.3/lib/rack/runtime.rb",
                     "function":"call",
                     "lineno":22,
                     "in_app":false,
                     "filename":"rack/runtime.rb",
                     "pre_context":[
                        "\n",
                        "    def call(env)\n",
                        "      start_time = Utils.clock_time\n"
                     ],
                     "context_line":"      status, headers, body = @app.call(env)\n",
                     "post_context":[
                        "      headers = Utils::HeaderHash[headers]\n",
                        "\n",
                        "      request_time = Utils.clock_time - start_time\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.3/lib/rack/method_override.rb",
                     "function":"call",
                     "lineno":24,
                     "in_app":false,
                     "filename":"rack/method_override.rb",
                     "pre_context":[
                        "        end\n",
                        "      end\n",
                        "\n"
                     ],
                     "context_line":"      @app.call(env)\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    def method_override(env)\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_dispatch/middleware/request_id.rb",
                     "function":"call",
                     "lineno":27,
                     "in_app":false,
                     "filename":"action_dispatch/middleware/request_id.rb",
                     "pre_context":[
                        "    def call(env)\n",
                        "      req = ActionDispatch::Request.new env\n",
                        "      req.request_id = make_request_id(req.x_request_id)\n"
                     ],
                     "context_line":"      @app.call(env).tap { |_status, headers, _body| headers[X_REQUEST_ID] = req.request_id }\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    private\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_dispatch/middleware/remote_ip.rb",
                     "function":"call",
                     "lineno":81,
                     "in_app":false,
                     "filename":"action_dispatch/middleware/remote_ip.rb",
                     "pre_context":[
                        "    def call(env)\n",
                        "      req = ActionDispatch::Request.new env\n",
                        "      req.remote_ip = GetIp.new(req, check_ip, proxies)\n"
                     ],
                     "context_line":"      @app.call(req.env)\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    # The GetIp class exists as a way to defer processing of the request data\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/sprockets-rails-3.2.2/lib/sprockets/rails/quiet_assets.rb",
                     "function":"call",
                     "lineno":13,
                     "in_app":false,
                     "filename":"sprockets/rails/quiet_assets.rb",
                     "pre_context":[
                        "        if env['PATH_INFO'] =~ @assets_regex\n",
                        "          ::Rails.logger.silence { @app.call(env) }\n",
                        "        else\n"
                     ],
                     "context_line":"          @app.call(env)\n",
                     "post_context":[
                        "        end\n",
                        "      end\n",
                        "    end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.6/lib/rails/rack/logger.rb",
                     "function":"call",
                     "lineno":26,
                     "in_app":false,
                     "filename":"rails/rack/logger.rb",
                     "pre_context":[
                        "        request = ActionDispatch::Request.new(env)\n",
                        "\n",
                        "        if logger.respond_to?(:tagged)\n"
                     ],
                     "context_line":"          logger.tagged(compute_tags(request)) { call_app(request, env) }\n",
                     "post_context":[
                        "        else\n",
                        "          call_app(request, env)\n",
                        "        end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/tagged_logging.rb",
                     "function":"tagged",
                     "lineno":71,
                     "in_app":false,
                     "filename":"active_support/tagged_logging.rb",
                     "pre_context":[
                        "    delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter\n",
                        "\n",
                        "    def tagged(*tags)\n"
                     ],
                     "context_line":"      formatter.tagged(*tags) { yield self }\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    def flush\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/tagged_logging.rb",
                     "function":"tagged",
                     "lineno":28,
                     "in_app":false,
                     "filename":"active_support/tagged_logging.rb",
                     "pre_context":[
                        "\n",
                        "      def tagged(*tags)\n",
                        "        new_tags = push_tags(*tags)\n"
                     ],
                     "context_line":"        yield self\n",
                     "post_context":[
                        "      ensure\n",
                        "        pop_tags(new_tags.size)\n",
                        "      end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/tagged_logging.rb",
                     "function":"block in tagged",
                     "lineno":71,
                     "in_app":false,
                     "filename":"active_support/tagged_logging.rb",
                     "pre_context":[
                        "    delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter\n",
                        "\n",
                        "    def tagged(*tags)\n"
                     ],
                     "context_line":"      formatter.tagged(*tags) { yield self }\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    def flush\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.6/lib/rails/rack/logger.rb",
                     "function":"block in call",
                     "lineno":26,
                     "in_app":false,
                     "filename":"rails/rack/logger.rb",
                     "pre_context":[
                        "        request = ActionDispatch::Request.new(env)\n",
                        "\n",
                        "        if logger.respond_to?(:tagged)\n"
                     ],
                     "context_line":"          logger.tagged(compute_tags(request)) { call_app(request, env) }\n",
                     "post_context":[
                        "        else\n",
                        "          call_app(request, env)\n",
                        "        end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.6/lib/rails/rack/logger.rb",
                     "function":"call_app",
                     "lineno":38,
                     "in_app":false,
                     "filename":"rails/rack/logger.rb",
                     "pre_context":[
                        "          instrumenter = ActiveSupport::Notifications.instrumenter\n",
                        "          instrumenter.start \"request.action_dispatch\", request: request\n",
                        "          logger.info { started_request_message(request) }\n"
                     ],
                     "context_line":"          status, headers, body = @app.call(env)\n",
                     "post_context":[
                        "          body = ::Rack::BodyProxy.new(body) { finish(request) }\n",
                        "          [status, headers, body]\n",
                        "        rescue Exception\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_dispatch/middleware/show_exceptions.rb",
                     "function":"call",
                     "lineno":33,
                     "in_app":false,
                     "filename":"action_dispatch/middleware/show_exceptions.rb",
                     "pre_context":[
                        "\n",
                        "    def call(env)\n",
                        "      request = ActionDispatch::Request.new env\n"
                     ],
                     "context_line":"      @app.call(env)\n",
                     "post_context":[
                        "    rescue Exception => exception\n",
                        "      if request.show_exceptions?\n",
                        "        render_exception(request, exception)\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/web-console-3.7.0/lib/web_console/middleware.rb",
                     "function":"call",
                     "lineno":20,
                     "in_app":false,
                     "filename":"web_console/middleware.rb",
                     "pre_context":[
                        "    end\n",
                        "\n",
                        "    def call(env)\n"
                     ],
                     "context_line":"      app_exception = catch :app_exception do\n",
                     "post_context":[
                        "        request = create_regular_or_whiny_request(env)\n",
                        "        return call_app(env) unless request.from_whitelisted_ip?\n",
                        "\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/web-console-3.7.0/lib/web_console/middleware.rb",
                     "function":"catch",
                     "lineno":20,
                     "in_app":false,
                     "filename":"web_console/middleware.rb",
                     "pre_context":[
                        "    end\n",
                        "\n",
                        "    def call(env)\n"
                     ],
                     "context_line":"      app_exception = catch :app_exception do\n",
                     "post_context":[
                        "        request = create_regular_or_whiny_request(env)\n",
                        "        return call_app(env) unless request.from_whitelisted_ip?\n",
                        "\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/notifications.rb",
                     "function":"instrument",
                     "lineno":168,
                     "in_app":false,
                     "filename":"active_support/notifications.rb",
                     "pre_context":[
                        "\n",
                        "      def instrument(name, payload = {})\n",
                        "        if notifier.listening?(name)\n"
                     ],
                     "context_line":"          instrumenter.instrument(name, payload) { yield payload if block_given? }\n",
                     "post_context":[
                        "        else\n",
                        "          yield payload if block_given?\n",
                        "        end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/sentry-rails-4.5.1/lib/sentry/rails/tracing.rb",
                     "function":"instrument",
                     "lineno":42,
                     "in_app":false,
                     "filename":"sentry/rails/tracing.rb",
                     "pre_context":[
                        "\n",
                        "            payload[:start_timestamp] = Time.now.utc.to_f if is_public_event\n",
                        "\n"
                     ],
                     "context_line":"            super(name, payload, &block)\n",
                     "post_context":[
                        "          end\n",
                        "        end\n",
                        "      end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/notifications/instrumenter.rb",
                     "function":"instrument",
                     "lineno":23,
                     "in_app":false,
                     "filename":"active_support/notifications/instrumenter.rb",
                     "pre_context":[
                        "        # some of the listeners might have state\n",
                        "        listeners_state = start name, payload\n",
                        "        begin\n"
                     ],
                     "context_line":"          yield payload\n",
                     "post_context":[
                        "        rescue Exception => e\n",
                        "          payload[:exception] = [e.class.name, e.message]\n",
                        "          payload[:exception_object] = e\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.6/lib/active_support/notifications.rb",
                     "function":"block in instrument",
                     "lineno":168,
                     "in_app":false,
                     "filename":"active_support/notifications.rb",
                     "pre_context":[
                        "\n",
                        "      def instrument(name, payload = {})\n",
                        "        if notifier.listening?(name)\n"
                     ],
                     "context_line":"          instrumenter.instrument(name, payload) { yield payload if block_given? }\n",
                     "post_context":[
                        "        else\n",
                        "          yield payload if block_given?\n",
                        "        end\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_controller/metal/instrumentation.rb",
                     "function":"block in process_action",
                     "lineno":34,
                     "in_app":false,
                     "filename":"action_controller/metal/instrumentation.rb",
                     "pre_context":[
                        "\n",
                        "      ActiveSupport::Notifications.instrument(\"process_action.action_controller\", raw_payload) do |payload|\n",
                        "        begin\n"
                     ],
                     "context_line":"          result = super\n",
                     "post_context":[
                        "          payload[:status] = response.status\n",
                        "          result\n",
                        "        ensure\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.2.6/lib/action_controller/metal/rescue.rb",
                     "function":"process_action",
                     "lineno":22,
                     "in_app":false,
                     "filename":"action_controller/metal/rescue.rb",
                     "pre_context":[
                        "\n",
                        "    private\n",
                        "      def process_action(*args)\n"
                     ],
                     "context_line":"        super\n",
                     "post_context":[
                        "      rescue Exception => exception\n",
                        "        request.env[\"action_dispatch.show_detailed_exceptions\"] ||= show_detailed_exceptions?\n",
                        "        rescue_with_handler(exception) || raise\n"
                     ]
                  },
                  {
                     "project_root":"/Users/dzaporozhets/Projects/creator-pairing/blog-no-auth",
                     "abs_path":"/Users/dzaporozhets/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/actionview-5.2.6/lib/action_view/path_set.rb",
                     "function":"find",
                     "lineno":48,
                     "in_app":false,
                     "filename":"action_view/path_set.rb",
                     "pre_context":[
                        "    end\n",
                        "\n",
                        "    def find(*args)\n"
                     ],
                     "context_line":"      find_all(*args).first || raise(MissingTemplate.new(self, *args))\n",
                     "post_context":[
                        "    end\n",
                        "\n",
                        "    def find_file(path, prefixes = [], *args)\n"
                     ]
                  }
               ]
            }
         }
      ]
   }
}

Screenshots (strongly suggested)

No frontend changes

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

Does this MR contain changes to processing or storing of credentials or tokens, authorization and authentication methods or other items described in the security review guidelines? If not, then delete this Security section.

  • [-] Label as security and @ mention @gitlab-com/gl-security/appsec
  • [-] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • [-] Security reports checked/validated by a reviewer from the AppSec team
Edited by Mayra Cabrera

Merge request reports