Grails 3 logging non String object as first argument - grails

In BootStrap.groovy in my Grails 3.3.2 app I get the following exception when logging:
groovy.lang.MissingMethodException: No signature of method: ch.qos.logback.classic.Logger.info() is applicable for argument types: (org.apache.http.message.BasicStatusLine) values: [HTTP/1.1 200 OK]
Here is the log statement:
log.info(resp.statusLine)
I know I can work around this by calling toString() on the info method but that is not a good solution because I may have lots of log statements that I may need to fix to workaround previously valid code. Is there a bug opened for this issue?

Grails 3 uses Logback as the logging library, and it has support for variable replacement that makes logging much more efficient.
Often users log statements like
log.debug('found ' + items.size() + ' items: ' + items)
This is expensive because the expression is concatenated into a single String before calling debug(), and if the level of that logger is not DEBUG or TRACE, then nothing will be logged, so if the concatenated String is large (or if this is called often) then that work is wasted. You can wrap the call in an enabled check:
if (log.isDebugEnabled()) {
log.debug('found ' + items.size() + ' items: ' + items)
}
but this clutters your code. With Logback though you're much better off doing this:
log.debug('found {} items: {}', items.size(), items)
Now you're just passing a simple String plus two args to interpolate at the specified positions, but only if the log statement is enabled for the logger's level. If not the call is almost a no-op.
For your logging statement, you should do this instead:
log.info('{}', resp.statusLine)
or
log.info('Status: {}', resp.statusLine)

Related

Is there a way to print a console message with Flutter?

I'm debugging an app, but I need to know some values in the fly, I was wondering if there's a way to print a message in console like console.log using Javascript.
I appreciate the help.
print() is probably what you are looking for. Here's some more info on debugging in flutter.
You can use
print()
function or
debugPrint()
The debugPrint() function can print large outputs.
There are more helpful methods in import 'dart:developer' library and one of them is log().
example:
int i = 5;
log("Index number is: $i");
//output
[log] Index number is: 5
void log(String message, {DateTime time, int sequenceNumber, int level
= 0, String name = '', Zone zone, Object error, StackTrace stackTrace})
Emit a log event.
This function was designed to map closely to the logging information
collected by package:logging.
[message] is the log message
[time] (optional) is the timestamp
[sequenceNumber] (optional) is a monotonically increasing sequence number
[level] (optional) is the severity level (a value between 0 and 2000); see the package:logging Level class for an overview of the
possible values
[name] (optional) is the name of the source of the log message
[zone] (optional) the zone where the log was emitted
[error] (optional) an error object associated with this log event
[stackTrace] (optional) a stack trace associated with this log event
Read more.:
print() is from dart:core and its implementation:
/// Prints a string representation of the object to the console.
void print(Object object) {
String line = "$object";
if (printToZone == null) {
printToConsole(line);
} else {
printToZone(line);
}
}
debugPrint():
/// Prints a message to the console, which you can access using the "flutter"
/// tool's "logs" command ("flutter logs").
///
/// If a wrapWidth is provided, each line of the message is word-wrapped to that
/// width. (Lines may be separated by newline characters, as in '\n'.)
///
/// By default, this function very crudely attempts to throttle the rate at
/// which messages are sent to avoid data loss on Android. This means that
/// interleaving calls to this function (directly or indirectly via, e.g.,
/// [debugDumpRenderTree] or [debugDumpApp]) and to the Dart [print] method can
/// result in out-of-order messages in the logs
// read more here: https://api.flutter.dev/flutter/foundation/debugPrint.html
DebugPrintCallback debugPrint = debugPrintThrottled;
/// Alternative implementation of [debugPrint] that does not throttle.
/// Used by tests.
debugPrintSynchronously(String message, { int wrapWidth })
/// Implementation of [debugPrint] that throttles messages. This avoids dropping
/// messages on platforms that rate-limit their logging (for example, Android).
void debugPrintThrottled(String message, { int wrapWidth })
Read more.
Note that only the print() is taking any type and print to the console. debugPrint() and log() only take String. So, you have to add .toString() or use string interpolation like I shown in provided example snippet.
I tend to do something similar to this
Foo foo;
try{
foo = _someMethod(); //some method that returns a new object
} catch (e) {
print('_someMethod: Foo Error ${foo.id} Error:{e.toString()}'); /*my custom error print message. You don't need brackets if you are printing a string variable.*/
}
Use debug print to avoid logging in production application.
debugPrint("Message");
You can also disable or change debug print implementation in main.dart or any other file like this:
debugPrint = (String message, {int wrapWidth})
{
debugPrintThrottled(message);//Or another other custom code
};
print, debugPrint and others have got some word limit restrictions, if you have something long to print on console, you can:
Create this method:
void printWrapped(String text) {
final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => print(match.group(0)));
}
Usage:
printWrapped("Your very long string ...");
Source
One more answer for Concatenate with String:
// Declaration
int number = 10;
//Button Action
RaisedButton(
child: Text("Subtract Me"),
onPressed: () {
number = number - 1;
print('You have got $number as result');
print('Before Value is ${number - 1} and After value is ${number + 1}');
},
),
//Output:
flutter: You have got 9 as result
flutter: Before Value is 8 and After value is 10
debugPrint()
Might as well use rather than print() as it attempts to reduce log line drop or being out of order on Android kernel
Refs:
Logging in Flutter
I think this might help you, because, I was also got stuck in many ways of knowing the output of my code in the dart file, hence I got the solution by following the steps, shown in the video.
https://www.youtube.com/watch?v=hhP1tE-IHos
here I have shown an instance of how it works after following the video.
check the left side column where it shows about the value which profile variable carry i.e., null
you can simply use print('whatever you want to print') same as console.log() in javascript.
for more info you can check here.
Note that the print() and log() options both add their own labels at the start of the line, and apply additional formatting that can cause long lines to be truncated. In the case of a dart:io app, you can bypass this interception and mangling entirely by going directly to stdout/stderr, etc. as in stdout.write(), stdout.writeln(), etc. Likewise if you are looking to log explicitly to one or the other. I ran into this issue when adding CLI args to a flutter application.
I use something like this. The print() function can print data up to some limit. So I use this log.
import 'dart:developer';
debugLog({String tag = '', required dynamic value}) {
log("TAG $tag : ${value.toString()}");
}

JQuery UI spinner spin event not as expected in Scala JS

When I define a spinner in ScalaJS and handle the spin value I am not able to get the new spin value in the event as I would have expected. According to the JQuery UI documentation the second parameter to the spin event is the ui object that contains a value attribute. So I defined a trait:
trait Number extends js.Object {
val value: Int = js.native
}
And then handle my spin event thus:
jQuery("#mySpinner").spinner(js.Dynamic.literal(spin = { (e: HTMLInputElement, ui: Number) =>
log("Change: " + ui.value)
}: js.ThisFunction1[HTMLInputElement, Number, Any]))
But the "value" attribute does not seem to be a member of the ui object as I get the exception below in my log statement. Can someone tell me what I am doing wrong?
uncaught exception: scala.scalajs.runtime.UndefinedBehaviorError: An
undefined behavior was detected: undefined is not an instance of
java.lang.Integer
You say e: HTMLInputElement but it should be e: Event
I suspect the problem is a combination of the previous comments. You are correct that, since you're using ThisFunction, the first element should be an Element of some sort. (Although, is it really an HTMLInputElement? That's a slightly unusual element type to put a spinner on.)
But that Element gets prepended to the function parameters, whereas you've got it replacing one.
In other words, you have
(e: HTMLInputElement, ui: Number)
but it needs to be
(elem: HTMLInputElement, e:Event, ui: Number)
in order to match the expected signature. So in practice, the system is trying to cast the value member of an Event, which of course doesn't exist, to Integer. It finds that value is undefined, tries to cast it to Integer, and boom.
I can't say I'm 100% certain (and IMO that ui parameter is just plain weird to begin with -- I'm a little suspicious of the jQueryUI documentation there), but that's my guess. Try fixing the signature of your call, and see if the error goes away...

Spring Data JPA with Security EvaluationContextExtensionSupport not working

I wanted to use Spring Data JPA's Security Extension support to perform a check on user's authority and accordingly fetch some values. I'm trying to do this as indicated here
Below is my code snippet
#RepositoryRestResource(collectionResourceRel = "ProductStatus", path = "ProductStatus")
public interface IProductStatusRepository extends CrudRepository<ProductStatusEntity, String> {
#Query("SELECT p FROM ProductStatusEntity " +
"?#{hasAuthority('ITManager') ? ' ' : ' WHERE ProductStatusCode NOT IN (\'VAL1\',\'VAL2\',\'VAL3\')'}")
List<ProductStatusEntity> findStatusesByAuthority();
}
I did declare the SecurityEvaluationContextExtension class and securityExtension bean by merely copy pasting the code. But still, the above piece of code doesnt work.
I always get a
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ?
I tried several options in playing around with ?#, :#, hasRole, hasAuthority etc. Nothing seem to work.
Any thoughts on this?
Well this one worked after several trial and errors
#Query("select p from ProductStatusEntity p where p.productStatusCode NOT IN ( ?#{hasAuthority('ITManager') ? ' ' : #settings.productStatusExceptions})")
List<ProductStatusEntity> findStatusesByAuthority();
The problem seems to be that SpEL is only being recognized if there is a WHERE clause specified.. Probably this could be improved.. not sure..

Query failed and the error.message is the data

A friend's query was failing. Fortunately, he was catching it in his fail callback (you DO have a fail callback for every server call, right?). Here's kind of what he had:
var getPersons = function(personsObservable) {
return EntityQuery.from('Person')
.using(manager).execute()
.then(querySucceeded).fail(queryFailed);
}
function queryFailed(error) {
var msg = 'Error retreiving data. ' + error.message;
logError(msg, error);
throw error;
}
The error.message simply showed the JSON data ... which looked a bit like this:
"[{"$id":"1","$type":"Person, ProjectName","Id":12,"FirstName":"Bob","LastName":"Smith","Email":"bs#contoso.com","Blog":"http://bs.contoso.com","Twitter": ..."
WAT?
He examined the error.XHR which provides the full AJAX XHR object used for this query. He could see that the HTTP Status Code was a 200 ... meaning that everything was cool from the server. The fact that he had real data pretty much said the same thing.
So why is Breeze failing? How does he diagnose the problem?
Breeze might be failing. But there's a good chance that the problem lies elsewhere. Usually if Breeze fails, there is a meaningful error message. This error message is not meaningful. But it does provide clues.
Check your success callback first
The fail callback can be invoked (1) if the operation fails or (2) if the success callback fails. If the operation fails, you've got a Breeze-related problem. If the success callback fails, you probably have an application code problem.
To determine which, put a breakpoint on the first line of the success callback (in his case, the first line of querySucceeded). If you hit the breakpoint, you know Breeze has done its bit and has handed off to you. Step through your callback to find the mistakes which are most likely yours and, therefore, easy to fix.
Check your custom EntityType constructors and initializers
In his case it did not get to the success callback. So something went wrong as Breeze tried to make cached entities out of the JSON data from the server. What could that be?
There are many potential causes. Could be a Breeze bug. Always best, though, to eliminate pilot error first. Did you write a custom constructor or initializer for this EntityType?
He did. He had an initializer that added a fullName calculated property to his Person. It looked sort of like this:
metadataStore.registerEntityTypeCtor('Person', null, personInitializer);
function personInitializer(person) {
person.fullName = ko.computed(function () {
return entity.firstName() + ' ' + person.lastName();
});
}
He didn't see a problem. But following diagnostic procedure, he put a breakpoint on the initializer.
Sure enough ... he had a typo ...
// "entity" does not exist. Null object error
return entity.firstName() + ' ' + person.lastName();
As soon as he changed entity to person, all was well.
I can't explain at the moment why the null object reference manifested as a Q promise fail error with the JSON Person data in the message. Strange stuff happens in JavaScript. But the clues were there:
server delivered the data
failed before getting to the success callback
data are about Person
have a Person initializer (or constructor)
Read the clues and you'll know where to look.
Hope this tip saves you from gray hair and a bald head.

Strange behavior of gorm finder

In a controller I have this finder
User.findByEmail('test#test.com')
And works.
Works even if I write
User.findByEmail(null)
But if i write
User.findByEmail(session.email)
and session.email is not defined (ergo is null) it throw exception
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
Is this behavior right?
If i evaluate "session.email" it give me null so I think it must work as it do when I write
User.findByEmail(null)
Even more strange....
If I run this code in groovy console:
import myapp.User
User.findByEmail(null)
It return a user that has null email but if I run the same code a second time it return
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
You can't use standard findBySomething dynamic finders to search for null values, you need to use the findBySomethingIsNull version instead. Try
def user = (session.email ? User.findByEmail(session.email)
: User.findByEmailIsNull())
Note that even if User.findByEmail(null) worked correctly every time, it would not necessarily give you the correct results on all databases as a findBySomething(null) would translate to
WHERE something = null
in the underlying SQL query, and according to the SQL spec null is not equal to anything else (not even to null). You have to use something is null in SQL to match null values, which is what findBySomethingIsNull() translates to.
You could write a static utility method in the User class to gather this check into one place
public static User byOptEmail(val) {
if(val == null) {
return User.findByEmailIsNull()
}
User.findByEmail(val)
}
and then use User.byOptEmail(session.email) in your controllers.
Jeff Brown from grails nabble forum has identified my problem. It's a GORM bug. see jira
More info on this thread
This jira too
I tried with debugger and it looks it should be working, as you write. Maybe the groovy itself is a little bit confused here, try to help it this way:
User.findByEmail( session['email'] )

Resources