airbrake / airbrake-js

Airbrake JavaScript Notifier
https://airbrake.io
MIT License
423 stars 139 forks source link

Project_id and project_key.. are not set on error report #38

Closed sebfie closed 11 years ago

sebfie commented 11 years ago

Hello,

I am trying to use this script to catch javascript error on my rails application. I configured it like this :

:javascript
    window.Airbrake = [];
    window.Airbrake.try = function(fn) { try { fn() } catch(er) { window.Airbrake.push(er); } };
    %script{ "defer" => "", "src" => "https://ssljscdn.airbrake.io/airbrake-js-tracekit-sourcemap.js", "data-airbrake-project-id" => "92691", "data-airbrake-project-key" => "4a662a0c82ca9210994173a1048d7023", "data-airbrake-project-environment-name" => "production" }

Right after the tag. And when an error is catched, it send to the url : https://api.airbrake.io/api/v3/projects/undefined/create-notice?key=undefin…2env%22%3A%7B%7D%2C%22params%22%3A%7B%7D%2C%22session%22%3A%7B%7D%7D%5D%7D

As you can see, the project_id is not find. It's due to this part of code :

function JsonpReporter(project_id, project_key, environment_name, processor_name, custom_context_data, custom_environment_data, custom_session_data, custom_params_data) {
  this.report = function(error_data) {
    var output_data = ReportBuilder.build(environment_name, processor_name, custom_context_data, custom_environment_data, custom_session_data, custom_params_data, error_data),
        document    = global.document,
        head        = document.getElementsByTagName("head")[0],
        script_tag  = document.createElement("script"),
        body        = JSON.stringify(output_data),
        cb_name     = "airbrake_cb_" + cb_count,
        prefix      = "https://api.airbrake.io", 
        url         = prefix + "/api/v3/projects/" + project_id + "/create-notice?key=" + project_key + "&callback=" + cb_name + "&body=" + encodeURIComponent(body);

    // Attach an anonymous function to the global namespace to consume the callback.
    // This pevents syntax errors from trying to directly execute the JSON response.
    global[cb_name] = function() { delete global[cb_name]; };
    cb_count += 1;

    function removeTag() { head.removeChild(script_tag); }

    script_tag.src     = url;
    script_tag.type    = "text/javascript";
    script_tag.onload  = removeTag;
    script_tag.onerror = removeTag;

    head.appendChild(script_tag);
  };
}

When it export this function, project_id is undefined. In fact, this export is executed before this :

(function(global){module.exports = function(client) {
  var scripts = global.document.getElementsByTagName("script"),
      i = 0, len = scripts.length, script,
      project_id,
      project_key,
      project_environment_name;

  for (; i < len; i++) {
    script = scripts[i];
    project_id = script.getAttribute("data-airbrake-project-id");
    project_key = script.getAttribute("data-airbrake-project-key");
    project_environment_name = script.getAttribute("data-airbrake-project-environment-name");
    if (project_id && project_key) {
      client.setProject(project_id, project_key);
    }
    if (project_environment_name) {
      client.setEnvironmentName(project_environment_name);
    }
  }
};

So, the project_id is not defined. I used this code to understand what is happening : https://ssljscdn.airbrake.io/airbrake-js-tracekit-sourcemap.js

sebfie commented 11 years ago

Why not to use :

Airbrake.getProject()[0] # to get project_id
Airbrake.getProject()[1] # to get project_key

?

benarent commented 11 years ago

Hi @Ditchou Thanks for reporting.

@vmihailenco and @duncanbeevers Can you give some insight here please.

duncanbeevers commented 11 years ago

The project id and project key are supposed to be pulled from the data attributes on the script tag, which it looks like you've set up correctly. The immediately-executed function you posted bootstraps the notifier, extracting these values from the data attributes and configuring the client with them.

I'd like to see why the bootstrap isn't pulling in those values for you. Could you throw a debugger into the bootstrapping snippet and see whether it finds the script tag in question and extracts values for project_id and project_key?

Alternatively, after the script has bootstrapped, you can manually set the project_id and project_key using

client.setProject("92691", "4a662a0c82ca9210994173a1048d7023")
sebfie commented 11 years ago

Hello,

Yes, it found the values and extract them doing this :

 client.setProject(project_id, project_key);

But the issue is that it's executed after : JsonpReporter()

And JsonpReporter.report() use project_id passed in attribute to the JsonpReporter function.

duncanbeevers commented 11 years ago

A new JsonpReporter instance is created for each error, initialized with the project_id and project_key as provided by client.getProject in the getReporter function.

Is there some other site where client.setProject is getting called with undefined values?

sebfie commented 11 years ago

No, client.setProject is called once with great parameters. You can not reproduce the issue? Just create an empty rails project.

duncanbeevers commented 11 years ago

I just spun up a trivial Rails app with your haml snippet, inserted a breakpoint in the report function and fired off a test error. I see the appropriate project_id and project_key referenced.

sebfie commented 11 years ago

Really? I tried with just this layout :

!!! 5
%html(lang="en"){"ng-app"=>"Pesto"}
  %head
    :javascript
      window.Airbrake = [];
      window.Airbrake.try = function(fn) { try { fn() } catch(er) { window.Airbrake.push(er); } };

    %script{ "defer" => "", "src" => "https://ssljscdn.airbrake.io/airbrake-js-tracekit-sourcemap.js", "data-airbrake-project-id" => "92691", "data-airbrake-project-key" => "4a662a0c82ca9210994173a1048d7023", "data-airbrake-project-environment-name" => "#{Rails.env}" }

    %meta(charset="utf-8")
    %meta(http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1")
    %meta(name="viewport" content="width=device-width, initial-scale=1.0")
    %title= content_for?(:title) ? yield(:title) : "Pesto"

  %body
    :javascript
      Airbrake.try(function() {
        document.headdd.test
      });

And it does not work... Do you use the same version of airbrake-js-tracekit-sourcemap.js ? (For information, i am working in local (not on a server))

duncanbeevers commented 11 years ago

I was able to reproduce this issue thanks to your report. This occurs when the shim has errors pushed to it before the client is in place. Those errors are reported before the client completes its bootstrap.

I've put a fix in place and opened a pull request against the main repository. We should be able to get new versions pushed out quickly.

In the meantime, you should be able to avoid this problem by simply removing the defer attribute from the airbrake script tag and loading the notifier synchronously until the new versions are made available.

vmihailenco commented 11 years ago

I tried it again today and it still does not work. @benarent , can we deploy new version?

vmihailenco commented 11 years ago

I can't reproduce this any more. Closing.