Integrating Instana error tracking into an Angular 2 application - javascript

I'm trying to integrate Instana into an application. More specifically I'm trying to send errors from my Angular app to Instana. I have my code 'working' so this is kind of a question about best practice.
Instana's Backend Correlation documentation defines functions in 'window' from what I understand. I've set something similar to this in my index.html.
<script>
(function(i,s,o,g,r,a,m){i['InstanaEumObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//eum.instana.io/eum.min.js','ineum');
ineum('apiKey', 'someKey');
ineum('traceId', 'backendTraceId'); //replace 'backendTraceId with the appropriate expression for retrieval
</script>
The issue I have is when I try to follow Instana's guide for Angular 2+ Integration regarding error tracking, where they call one of the methods that I can access from window. The guide just straight up calls the function ineum(...) by itself. When I try to do this, my project wouldn't compile.
class CustomErrorHandler implements ErrorHandler {
handleError(error) {
ineum('reportError', error);
// Continue to log caught errors to the console
console.error(error);
}
}
My current fix is: (<any>window).ineum('reportError', errorContext); But I was looking at another stack overflow question where they accessed window differently in their javascript.
Is typecasting window to 'any' a bad practice?
Is it better to try window['ineum'](...) or is that just a syntax preference?
Is it better to try to define functions in another file, say an Instana service of sorts, and then use that service in the index.html script and CustomErrorHandler or keep it in the window? (Though this one may be a little tricker for me to figure out)
Sorry for my confusion as this may not be an actual issue because my code is 'working' but I just want clarification on this. I'm not sure if I just didn't follow Instana's guides correctly but this was the best of what I could find. I tried reaching out via their contact page but I haven't received a response quite yet.

Instana has a demo application that shows to do this.
To summarize the parts that you would need:
Ensure that you have a local directory configured within your TypeScript config that allows definition of custom typings:
// common file name: tsconfig.app.json
{
// other configuration…
"typeRoots": [
// other configuration…
"./custom-typings"
]
}
Declare the global ineum function in a file within this directory:
// common file name globals.d.ts
declare function ineum(s: string, ...parameters: any[]): any;
The combination of these two steps will make TypeScript aware of the function. Now you can use ineum just like any other global.

Related

NodeJS - Dynamically import built in modules

I'd like to get a built in module (for example Math or path or fs), whether from the global object or require, I thought about doing something like this:
function getModuleByName(name) {
return global[name] || require(name);
}
Is there a way to check that it is indeed a module and not something else? Would this make a security problem?
Is there a way to check that it is indeed a module and not something else?
Other methods but here's an example:
function getModuleByName(name)
{
let module = null;
try {
module = require(name);
} catch (e) {
// Recommend Logging e Somewhere
}
return module;
}
This will graciously fail as null where the module does not exist, or return it.
Would this make a security problem?
Quite possibly, it depends on how it's used. I'd argue it is more of a general design issue however and would blanket say avoid doing it (without any context, you may have a very good reason).
You, like anyone, obviously have a finite amount of modules you could be loading. These modules have all been selected by yourself for your application for specific reasons, or are bundled into your node version natively and are expected parts of your environment.
What you are doing by introducing this functionality is adding the addition of unexpected elements in your environment. If you are using getModuleByName to access a third party library- you should know outright that library is available and as such there's no reason why you can't just require it directly.
--
If you do think your use case warrants this, please let me know what it is as I may never have encountered it before. I have used dynamic imports like the following:
https://javascript.info/modules-dynamic-imports
But that hasn't been for global packages/libraries, but for dynamic reference to modules built internally to the application (i.e. routing to different views, invokation of internal scripts).
These I have protected by ensuring filepaths can't be altered by whitelisting the target directories, making sure each script follows a strict interface per use case and graciously failing where a module doesn't exist (error output "this script does not exist" for the script usage and a 404 view for the routing example).

Debugging JavaScript code that uses ES6 Modules

TL;DR: How can I access variables/functions/names that are defined in ES Modules from the debugger?
More context: I'm a relatively experienced JavaScript programmer, but new to Modules. I've followed the tutorial at MDN here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules. They have a good set of examples here: https://github.com/mdn/js-examples/tree/master/modules
In that collection, say in the "basic-modules" example, (live code here: https://mdn.github.io/js-examples/modules/basic-modules/) there is, for example, a function called random in the file modules/square.js. Suppose I want to execute that function in the debugger, just to try it out, or because it's my code and I want to test/debug it, or I want to demonstrate to another coder what the function does. All the stuff you expect to do in a REPL or debugger. Is there a way to do that? I've tried both the Firefox debugger and the Chrome debugger, with no luck.
Back in the pre-Modules era, that code would be put into the global namespace (making access easy) or it would be locked up in an IIFE (making access impossible) or maybe in some home-made module system (access depends). I am hoping that the new Modules system still allows the debugger access to the names inside modules.
Thanks.
It says in the docs:
Last but not least, let's make this clear — module features are imported into the scope of a single script — they aren't available in the global scope. Therefore, you will only be able to access imported features in the script they are imported into, and you won't be able to access them from the JavaScript console, for example. You'll still get syntax errors shown in the DevTools, but you'll not be able to use some of the debugging techniques you might have expected to use.
To take your example from before, you'll need to invoke that function from a scope where it is visible, i.e where it's been imported:
import { random } from 'path/to/square.js'
debugger; // you should be able to invoke random() from here

Making compiled typescript code globally accessible

I've been working on a little project recently, and ran into this issue of actually having my project me accessible in the rest of the page.
Here's the deal:
It's a javascript router. Doing this just for the sake of interest. I've already set up my typescript compiler via grunt and my module loading and concatenation via grunt-requirejs.
Here's the grunt file: https://github.com/Forestdev/jsRoute/blob/master/gruntfile.js
The output, however, doesn't seem to generate any export to window. I have been googling as to how to export my code to window or anywhere really so that other javascript files could access it.
Could this be the problem with wrapper? Do I need to insert a custom wrapper for all of this? What's the general rule of thumb of making your typescript project global?
Edit:
Forgot to list the index file: https://github.com/Forestdev/jsRoute/blob/master/src/index.ts
Ignore the line with the new instance of an object. I want to export this object so that anyone else could create a new instance of it themselves.
Found a way to handle exposing to the global scope.
Within grunt build requirejs script I added a custom wrapper, which is:
wrap: {
start: '(function(global) {',
end: 'global.JSRoute = global.JSRoute || require("index").Router; }(window));'
}
This seems to fix the issue I had of exporting my script to a global scope. This also correctly loads the script on window load as well, so other scripts have access to it right away.
Hope this makes sense. Hopefully this is the correct way of doing it as well.

Debugging Unknown provider in minified angular javascript

I'm having a hard time trying to pinpoint which, of the very many, methods I have in my angular app that would be causing the error:
Uncaught Error: [$injector:unpr] Unknown provider: nProvider <- n
This only happens once the javascript has been bundled & minified by ASP.Net.
I have ensured that all the controllers, and any other DI, is using the minification-safe method, I.E My controllers/service etc are using the method:
appControllers.controller('myCtrl', ['$scope', function($scope){
//......
}]);
I've gone through every JS file in our app - there are a lot... and can't find anything that violates this way of injecting dependencies - though there must be one somewhere...
Is there a better way to pinpoint which method could be causing this error?
Thanks
For anyone else struggling with this problem, I found an easier solution. If you pull open your developer console (on chrome) and add a breakpoint where angular throws the error:
Then, on the stack trace on the right, click on the first "invoke" you see. This will take you to the invoke function, where the first parameter is the function angular is trying to inject:
I then did a search through my code for a function that looked like that one (in this case grep "\.onload" -R public), and found 8 places to check.
For anybody reading this, using Angular 1.3
You can now use Angular's ng-strict-di check like this:
<div ng-app="some-angular-app" ng-strict-di>
...
</div>
This will give you an appropriate error message if you didn't load your dependencies using the array syntax.
I had the same problem and I found a solution that could be helpful for the rest. What I propose is basically what I saw in the comments and docs. If you are using Angular 1.3.0 or above, you can use this:
<html ng-app="myApp" ng-strict-di>
<body>
I can add: {{ 1 + 2 }}.
<script src="angular.js"></script>
</body>
</html>
In my case, I have everything within a file app.js so the only thing I need to do for finding my DI problems is to add this little code at the end:
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
It's better documented in Angular Docs
I hope that helps. Good luck!
As mentioned in the comments, These are the steps I took to try and find my JS error.
If there is another, easier, solution, please feel free to post it and I may mark it as accepted.
Trying to debug minified code is a nightmare.
What I eventually did was copy my minified javascript, directly from the inspector in Chrome.
I then pasted the JS into http://www.jspretty.com/ - I had tried http://jsbeautifier.org/ but found their site froze with such large JS code.
Once it was 'pretty-fied' I created a test.js file in my solution and pasted the, now easier to read code, into it.
Quick step to comment out the #script tag in my _layout and add a link to the test.js file and I was ready to debug a now, far easier to read, chunk of Javascript.
It is still pretty awkward to traverse the call stack, though now you can see actual methods it makes it far less impossible.
Something that helped me solve this (finally!) was actually already in the angular docs! If you add the ng-strict-di attribute to your code wherever you define your ng-app, angular will throw a strict warning so you can more easily see what's going on in development mode. I wish that was the default!
See the argument list at the bottom of the ngApp docs.
https://docs.angularjs.org/api/ng/directive/ngApp
The way this works for me is the following:
1) have two test specification html files (unit test) minimized and plain
2) make sure the bundling of the files are in the same order as the plain spec file (JS script reference)
3) make sure to explicitly declare all dependencies (array or $inject declares see http://www.ozkary.com/2015/11/angularjs-minimized-file-unknown-provider.html)
When there is a mistake on the unit test (miminized reference) file, I can compare and make sure the reference of the files is in the correct order as the working file.
hope that help.
I had the similar issue and used lots of time to investigate and figured out it was the Chrome extension Batarang that was injecting the bad code and error in Angular looked exactly the same. It's really a pity it's so hard to find what exactly is causing the problem.
I had the similiar issue too. The solution is exacly the answer from ozkary point 3, that is to make sure to explicitly declare all dependencies including "resolve" part of your route.
Below is my code.
when('/contact/:id', {
controller: 'contactCtrl',
templateUrl: 'assets/partials/contact.html',
resolve: {
contact: ['ContactService', '$route', function(ContactService, $route) {
return ContactService.getContactDetail($route.current.params.id);
}]
}
})
For those who's bootstrapping their angularjs app.
angular.bootstrap(body, ['app'], { strictDi: true });
Don't forget to debug in non minified code and you should be able to figure out pretty quickly the malformed dependency injection.
The malformed injection is usually formatted like this :
...
.run([ function(ServiceInjected){
...
But should look more like this
...
.run(['ServiceInjected', function(ServiceInjected){
...
This is tested in angularjs 1.7.2

How to run jslint on the client?

For testing purposes, obviously not for production. What is the best way to do this?
Googling I found this tutorial, and of course the project on github.
For starters which files do I need to run:
// removed
and is there an API reference. I see there is a large comment block in jslint.js that seems to server this purpose but was wondering if there is something easier to read.
Because the client has no file access, I was planning on ajaxing the code in to get its contents.
Please never the mind, on why I want to do this on the client.
If you include the JSLint script you will have access to a single global variable, JSLINT. You can invoke it with a string and an optional map of options:
var valid = JSLINT(code, options);
The result will be true or false, depending on whether the code passed the check based on the provided options.
After this call you can inspect the JSLINT.errors property for an array of warnings, if any.
This is precisely what I have done to build JSLint integration into the editor in the articles on http://jslinterrors.com.
Have you looked at http://jshint.com/ ? Source is available here: https://github.com/jshint/jshint/
The browser bundle is available here: http://jshint.com/get/jshint-2.1.10.js and the docs describe how to call it (http://jshint.com/docs/)

Categories

Resources