I have a general question on how to proper implement a logging system in dart. I can't find reliable doc on it. Is logging lib up to date ? Thx !
I think this is the simplest way to set it up
import 'package:logging/logging.dart' show Logger, Level; // every library
import 'package:quiver_log/log.dart'; // library containing main
final _log = new Logger('bwu_model.server.main'); // every library
// main
void main() {
Logger.root.level = Level.FINEST;
var appender = new PrintAppender(BASIC_LOG_FORMATTER);
appender.attachLogger(Logger.root);
// actual logging
_log.info('Pub session initialized.');
}
Related
I need to determine the browser timezone. I tried to follow this post but does not work (Vaadin 20). Here is my code:
ZoneId myZoneId;
...
UI.getCurrent().getPage().retrieveExtendedClientDetails(extendedClientDetails -> {
myZoneId = ZoneId.of(extendedClientDetails.getTimeZoneId());
});
// here myZoneId has value null.
So I tried to do it myself, initially simply displaying it.
UI.getCurrent().getPage()
.executeJs("return Intl.DateTimeFormat().resolvedOptions().timeZone;")
.then(value -> Notification.show(value.asString()));
It works and I read "Europe/Rome", but its value does not seem something that I can map to a ZoneId in Java.
I could explore a little more the Javascript zone object but I also was unable to find where my code actually went to debug it with chrome debugger (there is no mention in Vaadin doc where the code goes).
I could work on the returned value and try to interpret it but I would like to avoid reinventing the wheel.
Do anybody has any code that works?
retrieveExtendedClientDetails is an asynchronous call, thus the result is available inside the callback and not right after firing the callback (on the place you commented).
Also, UI.getCurrent() could return null if called too soon, f.e. in a constructor.
retrieveExtendedClientDetails makes a client roundtrip the first time it is run (docs).
If already obtained, the callback is called directly. Otherwise, a client-side roundtrip will be carried out.
That means you could try to run it when initialising the UI and later you should have it ready right away after firing.
#SpringComponent
public class MyVaadinServiceInitListener implements VaadinServiceInitListener {
#Override
public void serviceInit(ServiceInitEvent event) {
event.getSource().addUIInitListener(uiEvent -> {
var ui = event.getUI();
ui.getPage().retrieveExtendedClientDetails(detail -> {});
});
}
}
Another solution is to read the zone inside the callback.
Europe/Rome is fine for Java.
You can simply call:
ZoneId.of("Europe/Rome");
Thanks to everybody!
Finally the main problem was not retrieving the time zone from the client but matching it against the list of available time zones returned by ZoneId.getAvailableZoneIds(). The fact is that there were multiple timezone for CEST (Central Europe) as well as any other country. I counted 7 for Brazil that only has 5 time zones!
Honestly I am little ignorant about time zones (world would be quite simpler if we could use only GMT and adjust our schedules accordingly). The solution was to digest the timezone list using the name. I do not know if this is right or wrong, but it is simple and works, despite the fact that if I choose CEST I do not know if it will be Rome, Berlin or whatever else. Does it matter?
Here is the complete code if somebody should one day need a
package net.cbsolution.scc.vaadin.comps;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.ItemLabelGenerator;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.data.renderer.TemplateRenderer;
import java.time.ZoneId;
import java.time.format.TextStyle;
import java.util.*;
import java.util.stream.Collectors;
public class TimeZoneSelector extends ComboBox<ZoneId> {
private Locale locale = UI.getCurrent().getLocale();
public TimeZoneSelector() {
// Digest the timezone list
final Map<String, ZoneId> cleanMap = new HashMap<>();
ZoneId.getAvailableZoneIds().stream().map(z -> ZoneId.of(z)).forEach(z -> cleanMap.put(print(z), z));
cleanMap.values().stream().collect(Collectors.toList());
setWidth("20em");
setDataProvider(new ListDataProvider<>(cleanMap.values().stream().collect(Collectors.toList())));
setRenderer(TemplateRenderer.<ZoneId>of("<span>[[item.print]]</span>")
.withProperty("print", tz -> print(tz))
);
setItemLabelGenerator((ItemLabelGenerator<ZoneId>) item -> print(item));
}
protected String print(ZoneId zoneId) {
return zoneId.getDisplayName(TextStyle.FULL, UI.getCurrent().getLocale());
}
#Override
protected void onAttach(AttachEvent attachEvent) {
UI.getCurrent().getPage().retrieveExtendedClientDetails(details -> {
TimeZone uiTimeZone = TimeZone.getTimeZone(details.getTimeZoneId());
setValue(ZoneId.of(uiTimeZone.getID()));
});
}
}
try this
//Read the timezone and store in into the session class
if(UI.getCurrent() != null) {
UI.getCurrent().getPage().retrieveExtendedClientDetails(details -> {
// Set the time zone
TimeZone uiTimeZone = TimeZone.getTimeZone(details.getTimeZoneId());
});
};
I'm trying to learn how to implement logging using the examples/tutorial in:
http://blog.dartwatch.com/2013/05/campaign-to-use-real-logging-instead-of.html#comment-form
But having imported the libraries this line in main will not compile because the class 'PrintHandler' is not recognized and Google has not been a help in this case. My server application consists of a main and three classes. I'm new at Dart. Below I've extracted the logging code that I added.
In what library is 'PrintHandler'? Is this a class I need to write?
library server;
import 'package:logging_handlers/logging_handlers_shared.dart';
import 'package:logging/logging.dart';
final _serverLogger = new Logger("server"); // top level logger
void main() {
Logger.root.onRecord.listen(new PrintHandler()); // default PrintHandler
_serverLogger.fine("Server created");
}
class A {
}
class B {
}
class C {
}
It looks like the class was changed to LogPrintHandler but the tutorial and documentation were not updated.
To my best knowledge, RollingFileAppender in log4j2 will not roll over at the specified time (let's say - at the end of an hour), but at the first log event that arrives after the time threshold has been exceeded.
Is there a way to trigger an event, that on one hand will cause the file to roll over, and on another - will not append to the log (or will append something trivial, like an empty string)?
No there isn't any (built-in) way to do this. There are no background threads monitoring rollover time.
You could create a log4j2 plugin that implements org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy (See the built-in TimeBasedTriggeringPolicy and SizeBasedTriggeringPolicy classes for sample code.)
If you configure your custom triggering policy, log4j2 will check for every log event whether it should trigger a rollover (so take care when implementing the isTriggeringEvent method to avoid impacting performance). Note that for your custom plugin to be picked up, you need to specify the package of your class in the packages attribute of the Configuration element of your log4j2.xml file.
Finally, if this works well for you and you think your solution may be useful to others too, consider contributing your custom triggering policy back to the log4j2 code base.
Following Remko's idea, I wrote the following code, and it's working.
package com.stony;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.rolling.*;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
#Plugin(name = "ForceTriggerPolicy", category = "Core")
public class ForceTriggerPolicy implements TriggeringPolicy {
private static boolean isRolling;
#Override
public void initialize(RollingFileManager arg0) {
setRolling(false);
}
#Override
public boolean isTriggeringEvent(LogEvent arg0) {
return isRolling();
}
public static boolean isRolling() {
return isRolling;
}
public static void setRolling(boolean _isRolling) {
isRolling = _isRolling;
}
#PluginFactory
public static ForceTriggerPolicy createPolicy(){
return new ForceTriggerPolicy();
}
}
If you have access to the Object RollingFileAppender you could do something like:
rollingFileAppender.getManager().rollover();
Here you can see the manager class:
https://github.com/apache/logging-log4j2/blob/d368e294d631e79119caa985656d0ec571bd24f5/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
I've been trying to find a line and print it out on this website: http://www.easports.com/player-hub/360/Its+McDoom
Right now it prints out everything on the website, but I cannot find the line I am looking for. I am trying to print out "H2h Skill Points: 1053", but I cannot find anything like that in the console.
I only really want it to print that 1 line, not the whole thing, but I can't even find it.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class ElectronicArtsStatHub {
/**
* #param args
*/
public static void main (String[] args) throws Exception{
URL oracle = new URL("http://www.easports.com/player-hub/360/Its+McDoom");
URLConnection yc = oracle.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
}
}
The first problem is that the information your trying to find isn't actually in the data you are currently outputting.
When you open the page in your browser you get the main page elements but then your browser then runs some Javascript code which presumably uses AJAX to get the stats and fill in the table.
The URLConnection receives the same data that your browser initially does and does not execute the Javascript so if you check your output that data your looking for isn't actually there at all.
Possible solutions include finding a different source for this data or executing the Javascript in Java possibly by using HTMLUnit
There may be some helpful infomation on this related question
Ok, so I'm looking at NLog. Based on the usage, my application would be tied to the logging framework. How do I overcome this?
Also, when using NLog, I have to write too much monkey-code for every class I'm using this framework on. Is it a good practice to make one static class and access it from anywhere in my application?
example:
//the monkey code
private static Logger logger = LogManager.GetCurrentClassLogger();
//the coupling.
logger.Log(/*...*/);
Create your own logging interface:
public interface IMyOwnLogger {
void Log(string message);
}
Create implementation:
public class NLogLogger : IMyOwnLogger {
void Log(string message) {
StackFrame frame = new StackFrame(1, false);
Logger logger = LogManager.GetLogger(frame.GetMethod().DeclaringType.FullName);
logger.Log(/*...*/);
}
}
Bind IMyOwnLogger to NLogLogger in your IOC container.
Inject where needed (or use IOC.Get<IMyOwnLogger>()).
EDIT:
Idsa made a comment about loosing calling class. Remember you can always use stack trace:
var method = (new StackTrace()).GetFrame(1).GetMethod()
and extract calling class from there.
EDIT:
This is how GetCurrentClassLogger in NLog looks like, so using StackTrace in our class doesn't create additional overhead:
[MethodImpl(MethodImplOptions.NoInlining)]
public static Logger GetCurrentClassLogger()
{
#if SILVERLIGHT
StackFrame frame = new StackTrace().GetFrame(1);
#else
StackFrame frame = new StackFrame(1, false);
#endif
return globalFactory.GetLogger(frame.GetMethod().DeclaringType.FullName);
}
Personally, I avoid tying any logging framework to my code by using
TraceSource to instrument my code. I then use a logging framework (typically Enterprise Library's Logging Application Block) to "listen" to trace output at runtime and do whatever is necessary with that information. (i.e. write to a database, send emails, etc)