When adding New Relic APM to track Parse Server, the calls to Cloud Code functions and Classes are displayed as:
/parse/classes/:className
/parse/functions/:functionName
Instead I want to display them as:
/parse/classes/myClass
/parse/functions/myFunction
For Cloud Code function calls I can set the transaction name:
Parse.Cloud.define("myFunction", async(request) => {
newrelic.setTransactionName("myFunction");
//...
});
But how can I track the names of all the calls to classes?
The New Relic Node.js agent has an auto-naming feature for transactions that can't be turned off*.
From the docs:
The only important thing to know about New Relic's support for Express, Restify, or Hapi is that if you're dissatisfied with the names it comes up with, you can use the API calls described below to come up with more descriptive names.
So the solution was to override these default name rules by adding custom name rules to newrelic.js. The trick is to use the regex group substitute as the name.
rules: {
name: [
// post /parse/classes/:classeName
// get /parse/classes/:classeName/:objectId
{
pattern: '^(\/parse\/classes\/[_0-9A-Za-z]*)(\/.*)*',
name: '\\1'
},
// post /parse/functions/:functionName
{
pattern: '^(\/parse\/functions\/.*)$',
name: '\\1'
},
// post /parse/files/:filename
// get /parse/files/:appId/:filename
{
pattern: '^(\/parse\/files)\/.*$',
name: '\\1'
}
]
}
The pattern above groups the calls by class name, ignoring the object ID that is sometimes appended. That makes it also unnecessary to add a setTransactionName for every Cloud Code function.
*It can be turned off for the Java agent, but that option does not seem to exists for the Node.js agent.
Related
In one of my use case, i have all my route information in a json file and i want to read the file and create the routes accordingly.
for example,
if i have declared route like this in my json config file
{
"config": [
{
"routeSrcSystem": "System1",
"routes": [
{
"fromRoute": {
"type": "default",
"typeValue": "direct:CMStart"
},
"toRoute": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System1/inboundMessage"
}
}
]
}
]
}
then i able to create the routes as below dynamically. but here though its dynamic,the route definition is not dynamic because i have used one "from" and one "to" definition but parameter for this definition i am passing dynamically.
public class GenerateRouter extends RouteBuilder {
private RoutesMetadata routesMetadata;
public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
super(context);
this.routesMetadata=routesMetadata;
}
#Override
public void configure() throws Exception {
from(routesMetadata.getFromRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue());
}
}
But i would like to do the route definition itself dynamically. for example, i have route config like this,
{
"config": [
{
"routeSrcSystem": "System1",
"routes": [
{
"fromRoute": {
"type": "default",
"typeValue": "direct:CMStart"
},
"toRoute1": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System1/inboundMessage"
}
"toRoute2": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System2/inboundMessage"
}
}
]
}
]
}
then in my route definition i need to add one more "to" definition dynamically. its just example. it could be more dynamic. for example, configuration can be changed to introduce "process" or "bean" or "class" definition. so based on the config, we need to decide how many "to" to be created and how many "process" to be created and etc. I might need to call the next rest end point after some validation and etc and some times i need to call kafka to put the message in queue. i do see an option to list all routes in a list and execute it but i think we need to have flexibility to add process or to or class definition before we call next end point and this has to be based on configuration.
public class GenerateRouter extends RouteBuilder {
private RoutesMetadata routesMetadata;
public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
super(context);
this.routesMetadata=routesMetadata;
}
#Override
public void configure() throws Exception {
from(routesMetadata.getFromRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue());
}
}
I saw some information where route definition itself can be defined dynamically and i am doing research on it. but meantime i would like to post this here to get experts opinion. Also, please suggest whether I am using the camel on right way? because in my use case i am thinking to add "to" definition to which pass the class name dynamically based on configuration file, so that application developer can do their logic for transformation, enrich or manipulation in this class on the fly before deliver to target system. please let me know if we have any better approach. also, let me know whether XML way of doing is good way or defining own config file in json format is a good way to create dynamic route.
i am planning to read the json file and create a router definition as a string dynamically. but i would need to load this string as a definition in context it seems. i think i am missing this part.
.to("class:com.xxx.camel.layoutTransform?method=layout()")
if we provide all these configurations in xml file and if camel supports to create the route definition automatically using this file then we can consider this option as well.
Below is the one of the way from another source to create the router definition using XML file. within the XML, we have router information defined and this xml considered as a string and this string is converted as router-definition object and finally added into context.
<routes
xmlns=\"http://camel.apache.org/schema/spring\">
<route>
<from uri='direct:c'/>
<to uri='mock:d'/>
</route>
</routes>
CamelContext context = new DefaultCamelContext();
context.setTracing(true);
String xmlString = "<routes xmlns=\"http://camel.apache.org/schema/spring\"><route><from uri='direct:c'/><to uri='mock:d'/></route></routes>";
InputStream is = new ByteArrayInputStream(xmlString.getBytes());
RoutesDefinition routes = context.loadRoutesDefinition(is);
context.addRouteDefinitions(routes.getRoutes());
context.start();
ProducerTemplate template = null;
template = context.createProducerTemplate();
template.start();
template.sendBody("direct:c", "HelloC");
Thread.sleep(10000);
context.stop();
I would like to do the similar concept using java dsl definition as a string.
for example, if i have string as below then can this be converted as a router definition?
String dslString = "from("direct:starting").to("seda:end")";
Here is my use case. Sometime, we want to call 2 http services as below
from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2")
Somtimes we might need to call 3 services as like below
from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2").to("http://localhost:8080/service3")
sometimes we need to do transformation before we invoke service2 as like below.
from("direct:start").to(http://localhost:8080/service1).to("class:com.xxx.yyy").to("http://localhost:8080/service2").to("http://localhost:8080/service3")
In the even driven architecture, we will have set of routes must be defined for each event types. so the idea is, if we define these routes in a table for each event type, then at the time of service start up all the routes will be loaded in context and will be started. I am able to do the same in XML DSL way but trying to do the same in java DSL.
Thanks in advance!
Camel supports defining all details about routes in a particular XML-based format. This page has links to that (and other) DSLs.
You could definitely come up with your own DSL and build routes dynamically, but that's a lot of work if you want to support all the things a full Camel DSL would support. I would suspect that is not the right solution for whatever your use-case.
If you have certain patterns to your routes, you can create fairly dynamic Camel route-builders that are driven by some configuration. To make this concrete, let's say you have many use cases that follow a very similar pattern... say, consumer data from files in a folder, do a few transformations from a menu of (say) 10-15 transformations, and then sends output to one of many queues.
Since you have various possible combinations, it could make sense to configure those details in file etc. and then build some routes off that. The trade-off is not different from any other place where you have to decide if it is clearer to just code the 10 things you want, or to make something more complex but generic.
Essentially, you would still be creating a DSL or sorts, but one that is closer to your use case.
I know I can enableTracing on the Angular 2 router:
export const routing: ModuleWithProviders =
RouterModule.forRoot(routes, { enableTracing: true });
Is there any way to programatically set that value?
I have a config.json file that has a number of application settings. I would like to include a boolean property that can be used to control whether tracing is on or not. I'd rather not have the customer have the ability to modify the file that contains my routes, but still have the ability to turn on tracing to help debug edge cases that didn't get caught by tests.
I'm OK with having to restart the application, but not OK with having to rebuild.
[Update]
After looking at the router source, it doesn't look do-able without a pull request. Simple explanation of what the change would need to be:
In router.ts, add a public property called tracing: boolean
In router_module.ts::setupRouter:
Change
if (opts.enableTracing) {
to
router.tracing = opts.enableTracing</pre>
Change the observable:
router.events.subscribe(e => { ...
to
router.events
.filter(e => router.tracing)
.subscribe(e => { ...</li>
3. Probably need to add some validation on the tracing property.
With these changes, one could import Router and then set the router.tracing property to turn it on and off.
I have no idea what the performance difference is between emitting all of the events with no subscriber and emitting all of the events with a filtered subscription.
For now there is no explicit way to do it programmatically. Our workaround is to enable it only for local development so that we can get all the details/exception-stacktrace etc. Something like:
let routes = [{path: ..., component : ...}, ...];
RouterModule.forRoot(routes, {
enableTracing: /localhost/.test(document.location.host)
});
I activated user confirmation for FOSUserBundle. But I don't want to take the response from the original listener
$url = $this->router->generate('fos_user_registration_check_email');
$event->setResponse(new RedirectResponse($url));
I want to chose another route. I tried to extend the EventListener
namespace Acme\MyBundle\EventListener;
use FOS\UserBundle\EventListener\EmailConfirmationListener as BaseListener;
// ...
class EmailConfirmationListener extends BaseListener
{
public function onRegistrationSuccess(FormEvent $event)
{
$url = $this->router->generate('fos_user_registration_check_email');
$event->setResponse(new RedirectResponse($url));
}
}
Unfortunately, EventListeners don't seem to be extendable, just as Controllers or Forms are. (Just in case you wonder: of course my bundle is a child of the FOSUserBundle.)
So I want to avoid editing those two lines directly in the vendor folder (as it would be very bad practice to do so!). So what are my ways out of this calamity?
Just override the service fos_user.listener.email_confirmation by creating a service with the same name in your config.yml ...
# app/config/config.yml
services:
fos_user.listener.email_confirmation:
class: "Acme\MyBundle\EventListener\EmailConfirmationListener"
arguments: ["#fos_user.mailer", "#fos_user.util.token_generator", "#router", "#session"]
tags:
- { name: kernel.event_subscriber }
... or even cleaner - create a parameter that's being used by your service:
parameters:
my.funky_parameter.class: "Acme\MyBundle\EventListener\EmailConfirmationListener"
services:
fos_user.listener.email_confirmation:
class: "%my.funky_parameter.class%"
# ...
... or inside your bundle's xml/yml/php configuration file loaded by the bundle's extension. Make sure your bundle is being registered after FOSUserBundle in AppKernel.php when choosing this way.
... or the best method:
change the original service's class name in a compiler pass as the documentation chapter How to Override any Part of a Bundle suggests.
Maybe take a dive into the chapter How to work with Compiler Passes before choosing this option.
EDIT: See below for my current problem. The top portion is a previous issue that I've solved but is somewhat related
I need to modify the input values passed to my controller before it actually gets there. I am building a web app that I want to be able to support multiple request input types (JSON and XML initially). I want to be able to catch the input BEFORE it goes to my restful controller, and modify it into an appropriate StdClass object.
I can't, for the life of me, figure out how to intercept and modify that input. Help?
For example, I'd like to be able to have filters like this:
Route::filter('json', function()
{
//modify input here into common PHP object format
});
Route::filter('xml', function()
{
//modify input here into common PHP object format
});
Route::filter('other', function()
{
//modify input here into common PHP object format
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
Route::when('*.xml', 'xml'); //Any route with '.json' appended uses json filter
Route::when('*.other', 'other'); //Any route with '.json' appended uses json filter
Right now I'm simply doing a Input::isJson() check in my controller function, followed by the code below - note that this is a bit of a simplification of my code.
$data = Input::all();
$objs = array();
foreach($data as $key => $content)
{
$objs[$key] = json_decode($content);
}
EDIT: I've actually solved this, but have another issue now. Here's how I solved it:
Route::filter('json', function()
{
$new_input = array();
if (Input::isJson())
{
foreach(Input::all() as $key => $content)
{
//Do any input modification needed here
//Save it in $new_input
}
Input::replace($new_input);
}
else
{
return "Input provided was not JSON";
}
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
The issue I have now is this: The path that the Router attempts to go to after the filter, contains .json from the input URI. The only option I've seen for solving this is to replace Input::replace($new_input) with
$new_path = str_replace('.json', '', Request::path());
Redirect::to($new_path)->withInput($new_input);
This however leads to 2 issues. Firstly I can't get it to redirect with a POST request - it's always a GET request. Second, the data being passed in is being flashed to the session - I'd rather have it available via the Input class as it would be with Input::replace().
Any suggestions on how to solve this?
I managed to solve the second issue as well - but it involved a lot of extra work and poking around... I'm not sure if it's the best solution, but it allows for suffixing routes similar to how you would prefix them.
Here's the github commit for how I solved it:
https://github.com/pcockwell/AuToDo/commit/dd269e756156f1e316825f4da3bfdd6930bd2e85
In particular, you should be looking at:
app/config/app.php
app/lib/autodo/src/Autodo/Routing/RouteCompiler.php
app/lib/autodo/src/Autodo/Routing/Router.php
app/lib/autodo/src/Autodo/Routing/RoutingServiceProvider.php
app/routes.php
composer.json
After making these modifications, I needed to run composer dumpautoload and php artisan optimize. The rest of those files are just validation for my data models and the result of running those 2 commands.
I didn't split the commit up because I'd been working on it for several hours and just wanted it in.
I'm going to hopefully look to extend the suffix tool to allow an array of suffixes so that any match will proceed. For example,
Route::group(array('suffix' => array('.json', '.xml', 'some_other_url_suffix')), function()
{
// Controller for base API function.
Route::controller('api', 'ApiController');
});
And this would ideally accept any call matching
{base_url}/api/{method}{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?}{suffix}`
Where:
base_url is the domain base url
method is a function defined in ApiController
{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?} is a series of up to 5 optional variables as are added when registering a controller with Route::controller()
suffix is one of the values in the suffix array passed to Route::group()
This example in particular should accept all of the following (assuming localhost is the base url, and the methods available are getMethod1($str1 = null, $str2 = null) and postMethod2()):
GET request to localhost/api/method1.json
GET request to localhost/api/method1.xml
GET request to localhost/api/method1some_other_url_suffix
POST request to localhost/api/method2.json
POST request to localhost/api/method2.xml
POST request to localhost/api/method2some_other_url_suffix
GET request to localhost/api/method1/hello/world.json
GET request to localhost/api/method1/hello/world.xml
GET request to localhost/api/method1/hello/worldsome_other_url_suffix
The last three requests would pass $str1 = 'hello' and $str2 = 'world' to getMethod1 as parameters.
EDIT: The changes to allow multiple suffixes was fairly easy. Commit located below (please make sure you get BOTH commit changes to get this working):
https://github.com/pcockwell/AuToDo/commit/864187981a436b60868aa420f7d212aaff1d3dfe
Eventually, I'm also hoping to submit this to the laravel/framework project.
I'm writing a front-end to my RESTful API using Backbone... and I'm really enjoying it so far. Learning this framework continues to be super interesting. However, I am now stumped on something that seems like, to me at least, that it should be straight forward.
I now have a single (and only) html page where the main application resides that lists one or more products. And, lets say it resides here: http://localhost/index.html
I would like to be able to switch from the product list view to the new product view (via click event on a button at the top). And that, from what I understand, I need to begin using a router for switching using the pattern described in How to switch views using Backbone.js.
Is view-switching what I need to be doing to achieve this behavior?
This looks hokey: http://localhost/index.html#product/newAnd, since I'm using [tornado](http://tornadoweb.org) as my web server for both my API and static content, I can't just implement a rewrite rule easily. I may switch to using nginx for static content in the near future, but I haven't yet. If I'm to use a router to switch views like when going from Review to Create (of CRUD operations), how do I change the URL/URI to look something more along the lines of thishttp://localhost/product/new
In order to receive hashless url changes, your browser has to support pushstate. If I am not mistaken, Backbone will fallback to using hashes if your browser does not support pushstate. You would initialize your router with the following in order to use pushstate in your application:
Backbone.history.start({pushState: true})
I like #alexanderb's use of view switching. Just MAKE sure when you are changing views, you dispose of them properly. Otherwise you will run into some complex problems that are difficult to debug. Read more here.
Yes, you need 2 things - Router and ApplicationViewManager (some class, that is responsible for changing the view).
define(function () {
var ViewManager = function () {
return {
show: _showView
};
};
function _showView(view) {
if (this.currentView) {
this.currentView.close();
}
this.currentView = view;
this.currentView.render();
$("#app").html(this.currentView.el);
}
return ViewManager;
});
In router, you do something like:
// router
var ApplicationRouter = Backbone.Router.extend({
initialize: function () {
this.viewManager = new ViewManager();
},
routes: {
'': 'dashboard',
'configure/sites/:id': 'configure'
},
dashboard: function () {
var app = require('./apps/DashboardApp');
app.run(this.viewManager);
},
configure: function (id) {
var app = require('./apps/ConfigureApp');
app.run(id, this.viewManager);
}
});
Some code examples, you can take from this repository.