Ask Questions and Find Answers
Important:
Ask is now read-only. You can review any existing questions and answers, but not add anything new.
But - don't panic! While ask is no more, we've replaced it with discuss - the new Liferay Discussion Forum! Read more here here or just visit the site here:
discuss.liferay.com
RE: Logging messages via JavaScript
Is there any way to replace this portlet code with frontend JavaScript?
I am aware of using services. The logger is invoked inside that service method:
Are there other options?
Thanks.
LogFactoryUtil.getLog("my.company.portlet").info("info");
I am aware of using services. The logger is invoked inside that service method:
Liferay.Service('/myportlet.tools/log-params', {
param1: "param1",
param2: "param2"
}, null);
In my simple portlet the custom service (service builder based) just for logging seems to be overkill.Are there other options?
Thanks.
I don't think so, I mean, at the end of the day they are two different contexts; one is the backend where there is no JS and no connection to one or more browsers that might be logging.
I'd like to recommend Sentry for frontend error tracking.
https://sentry.io/for/javascript/
Maybe this is overkill too, but it is at least worth to know that service. You can install it also on a local server.
Another idea is to add your own rest service. Works pretty well in Liferay 7.0 for us. Check out the "rest" module.
http://www.javasavvy.com/liferay-7-rest-webservices-tutorial/
https://sentry.io/for/javascript/
Maybe this is overkill too, but it is at least worth to know that service. You can install it also on a local server.
Another idea is to add your own rest service. Works pretty well in Liferay 7.0 for us. Check out the "rest" module.
http://www.javasavvy.com/liferay-7-rest-webservices-tutorial/
What I had in mind was rather some standard Liferay logger service which could be somehow employed.
Finally I replaced my service with the serveResource method in my portlet, which is triggered by XHR:
Portlet code:
It satisfies my needs. I only do not like the fact it needs to be implemented in every portlet requiring JavaScript based logging.
Finally I replaced my service with the serveResource method in my portlet, which is triggered by XHR:
<portlet:resourceurl var="loggerResourceURL" id="logger" />
<script>
document.getElementById("my-button").addEventListener("click", function() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "<%= loggerResourceURL%>");
xhr.send();
});
</script>
Portlet code:
@Override
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException {
String resourceId = resourceRequest.getResourceID();
switch (resourceId) {
case "logger":
ThemeDisplay themeDisplay = (ThemeDisplay) resourceRequest.getAttribute(WebKeys.THEME_DISPLAY);
User user = userLocalService.fetchUser(themeDisplay.getUserId());
LogFactoryUtil.getLog("my.company.portlet.MyCustomLogger").info(user.getEmailAddress());
break;
default:
super.serveResource(resourceRequest, resourceResponse);
}
}
It satisfies my needs. I only do not like the fact it needs to be implemented in every portlet requiring JavaScript based logging.
Jan TošovskýWell, you could write a webservice and call it from the frontend. In that case you'd need to pass in the context, e.g. portlet name etc. Plus, you'd need to trust the logging information coming from the browser. In case someone has tampered with it, you might end up with 1GB of logging information (doesn't take a lot of transfer volume with mod_gzip) or contexts that you've never heard of.
It satisfies my needs. I only do not like the fact it needs to be implemented in every portlet requiring JavaScript based logging.
Your own portlet here circumvents this problem by not logging any information from the browser, just the fact that it's been called. What would you expect to be logged in other cases?
I'd say the effort is minimal (and might be able to be extracted into a common library that doesn't rely on browser-provided information), while it saves you from a good attack vector.
Jan TošovskýIt satisfies my needs. I only do not like the fact it needs to be implemented in every portlet requiring JavaScript based logging.
Are you logging or auditing?
Because logging is not something you want to be doing; this will generate a lot of chatter back to your backend to log a message like "dave clicked a button" or "dave navigated to detail panel".
Normally one would log a service access point (but that is in the backend already) and that's enough.
I just can't see adding JS-based logging to every portlet in order to keep tracking the same unused junk that one normally logs...
David H NebingerThis! (emphasis mine)Jan TošovskýIt satisfies my needs. I only do not like the fact it needs to be implemented in every portlet requiring JavaScript based logging.
Are you logging or auditing?
Because logging is not something you want to be doing; this will generate a lot of chatter back to your backend to log a message like "dave clicked a button" or "dave navigated to detail panel".
Normally one would log a service access point (but that is in the backend already) and that's enough.
I just can't see adding JS-based logging to every portlet in order to keep tracking the same unused junk that one normally logs...
If it's logging: See my vulnerability warning further up. It can't be auditing, because this auditing could easily be prevented, faked or altered, as it relies on the browser to send truthful messages. But you can't trust anything coming from the browser, and you can't trust that anything will come in from the browser at all. IMHO you'd have to do auditing solely on the backend. And I assume that there it's best to handle all the details that you have available on a case-by-case basis. So: Sorry, there's no generic auditing that doesn't just flood you with "Dave considered to click a button", "Dave moved the mouse", "Now Dave clicked a button" ;)
Hi Olaf, you are right. After rereading your answer I finally got your point. Yes, my approach could be used as a new attack vector so now I understand why some Liferay logger service doesn't exist and never will.
Even our portlets are available only to registered users, I'll try to find a better solution (I'd rather transformed that alien JavaScript SPA into regular portlet to have a full control over it).
Even our portlets are available only to registered users, I'll try to find a better solution (I'd rather transformed that alien JavaScript SPA into regular portlet to have a full control over it).
I should clarify my use case:
So basically I am attaching event handler to some actions and passing all params to the backend, where these params are parsed and logged via standard backend methods.
In 6.2 I did it via ServiceBuilder-based project (and calling my service via JavaScript), but now during migrating to 7.x I reviewing old code and in this particular case the ServiceBuilder seems to be a overkill to me (= generating many classes, splitting modules into 'api', 'service' and 'web' parts). In my new solution I am achieving the same functionality with much lightweight component.
I mentioned it means repeating that backend code in every portlet. As there are only 3 such portlets in my case, it is rather a minor issue for me.
- There is an external link in my portlet. I'd like to log who clicked it.
- Some portlets in my portal are just containers for single 'page' JavaScript apps (generating outputs via 3rd party service). So my frontent is just JSP wrapper containg <div id="app"/> and the rendering is driven by the supplied JavaScript code. There is a request to log user preferences before submitting the form.
So basically I am attaching event handler to some actions and passing all params to the backend, where these params are parsed and logged via standard backend methods.
In 6.2 I did it via ServiceBuilder-based project (and calling my service via JavaScript), but now during migrating to 7.x I reviewing old code and in this particular case the ServiceBuilder seems to be a overkill to me (= generating many classes, splitting modules into 'api', 'service' and 'web' parts). In my new solution I am achieving the same functionality with much lightweight component.
I mentioned it means repeating that backend code in every portlet. As there are only 3 such portlets in my case, it is rather a minor issue for me.
Even this sounds like a mix of audit and user tracking...
If it is just user tracking, you might model how the other analytics providers deal w/ user event tracking.
If it is auditing, you could either do a centralized REST service or, for persistence sake you could still use Service Builder, you just wouldn't need the -web portion unless you were wanting to display the records. But the remote JSON web service would allow you to pass in relevant details and do what you needed, plus with the injected service context you wouldn't even need to pass the user's email address in...
If it is just user tracking, you might model how the other analytics providers deal w/ user event tracking.
If it is auditing, you could either do a centralized REST service or, for persistence sake you could still use Service Builder, you just wouldn't need the -web portion unless you were wanting to display the records. But the remote JSON web service would allow you to pass in relevant details and do what you needed, plus with the injected service context you wouldn't even need to pass the user's email address in...
Copyright © 2025 Liferay, Inc
• Privacy Policy
Powered by Liferay™