my question is similar to Why does java.util.logging.Logger print to stderr? post.
I want to use only one handler in my logging, where as it should print INFO statements on to out stream and WARNING & SEVERE onto error stream.
Is this possible ?
If I take two handlers for example,
one for out stream - and level as INFO
another for error stream - and level as WARNING/SEVERE in this case, application is showing messages twice
one with out stream and another with error stream.
So any solution ?
This is possible with one or two handlers. The missing part is that you need to create a filter for the OUT handler that limits the highest level. Also you need to make sure there are no other ConsoleHandlers attached to the root logger which can pollute your test. You can print the logger tree to see what handlers are attached.
Here is a proof of concept:
import java.io.PrintStream;
import java.util.logging.ConsoleHandler;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class OutErrorTest {
private static final Logger log = Logger.getLogger("");
public static void main(String[] args) {
LogManager.getLogManager().reset(); //A quick way to remove all handlers.
Handler out = newSystemOut();
Handler err = newSystemErr();
final Level fence = Level.WARNING;
out.setLevel(Level.ALL);
out.setFilter(new LessThanLevelFilter(fence));
err.setLevel(fence);
log.addHandler(out);
log.addHandler(err);
log.setLevel(Level.ALL);
log.finest("Finest Log");
log.finer("Finer Log");
log.fine("Fine Log");
log.config("Config Log");
log.info("Info Log");
log.warning("Warning Log");
log.severe("Severe Log");
}
private static Handler newSystemErr() {
return new ConsoleHandler();
}
private static Handler newSystemOut() {
Handler h = null;
final PrintStream err = System.err;
System.setErr(System.out);
try {
h = new ConsoleHandler(); // Snapshot of System.err
} finally {
System.setErr(err);
}
return h;
}
public static class LessThanLevelFilter implements Filter {
private final int lvl;
public LessThanLevelFilter(final Level max) {
this(max.intValue());
}
public LessThanLevelFilter(final int max) {
this.lvl = max;
}
#Override
public boolean isLoggable(LogRecord r) {
return r.getLevel().intValue() < lvl;
}
}
}
Related
Here is a sample of the code flow:
Trigger the process with an API specifying bulkSize and totalRecords.
Use those parameters to acquire data from DB
Create a processor with the bulkSize.
Send both the data and processor into a method which:
-iterates over the resultset, assembles a JSON for each result, calls a method if the final JSON is not empty and adds that final JSON to the process using processor.add() method.
This is where the outcome of the code is split
After this, if the concurrentRequest parameter is 0 or 1 or any value < (totalRecords/bulkSize), the processor.add() line is where the code stalls and never continues to the next debug line.
However, when we increase the concurrentRequest parameter to a value > (totalRecords/bulkSize), the code is able to finish the .add() function and move onto the next line.
My reasoning leads me to believe we might be having issues with our BulkProcessListener which is making the .add() no close or finish like it is supposed to. I would really appreciate some more insight about this topic!
Here is the Listener we are using:
private class BulkProcessorListener implements Listener {
#Override
public void beforeBulk(long executionId, BulkRequest request) {
// Some log statements
}
#Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
// More log statements
}
#Override
public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
// Log statements
}
}
Here is the createProcessor():
public synchronized BulkProcessor createProcessor(int bulkActions) {
Builder builder = BulkProcessor.builder((request, bulkListener) -> {
long timeoutMin = 60L;
try {
request.timeout(TimeValue.timeValueMinutes(timeoutMin));
// Log statements
client.bulkAsync(request, RequestOptions.DEFAULT,new ResponseActionListener<BulkResponse>());
}catch(Exception ex) {
ex.printStackTrace();
}finally {
}
}, new BulkProcessorListener());
builder.setBulkActions(bulkActions);
builder.setBulkSize(new ByteSizeValue(buldSize, ByteSizeUnit.MB));
builder.setFlushInterval(TimeValue.timeValueSeconds(5));
builder.setConcurrentRequests(0);
builder.setBackoffPolicy(BackoffPolicy.noBackoff());
return builder.build();
}
Here is the method where we call processor.add():
#SuppressWarnings("deprecation")
private void addData(BulkProcessor processor, String indexName, JSONObject finalDataJSON, Map<String, String> previousUniqueObject) {
// Debug logs
processor.add(new IndexRequest(indexName, INDEX_TYPE,
previousUniqueObject.get(COMBINED_ID)).source(finalDataJSON.toString(), XContentType.JSON));
// Debug logs
}
I am trying to implement the following use case as part of my akka learning
I would like to calculate the total streets in all cities of all states. I have a database that contain the details needed. Here is what i have so far
Configuration
akka.actor.deployment {
/CityActor{
router = random-pool
nr-of-instances = 10
}
/StateActor {
router = random-pool
nr-of-instances = 1
}}
Main
public static void main(String[] args) {
try {
Config conf = ConfigFactory
.parseReader(
new FileReader(ClassLoader.getSystemResource("config/forum.conf").getFile()))
.withFallback(ConfigFactory.load());
System.out.println(conf);
final ActorSystem system = ActorSystem.create("AkkaApp", conf);
final ActorRef masterActor = system.actorOf(Props.create(MasterActor.class), "Migrate");
masterActor.tell("", ActorRef.noSender());
} catch (Exception e) {
e.printStackTrace();
}
}
MasterActor
public class MasterActor extends UntypedActor {
private final ActorRef randomRouter = getContext().system()
.actorOf(Props.create(StateActor.class).withRouter(new akka.routing.FromConfig()), "StateActor");
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
getContext().watch(randomRouter);
for (String aState : getStates()) {
randomRouter.tell(aState, getSelf());
}
randomRouter.tell(new Broadcast(PoisonPill.getInstance()), getSelf());
} else if (message instanceof Terminated) {
Terminated ater = (Terminated) message;
if (ater.getActor().equals(randomRouter)) {
getContext().system().terminate();
}
}
}
public List<String> getStates() {
return new ArrayList<String>(Arrays.asList("CA", "MA", "TA", "NJ", "NY"));
};}
StateActor
public class StateActor extends UntypedActor {
private final ActorRef randomRouter = getContext().system()
.actorOf(Props.create(CityActor.class).withRouter(new akka.routing.FromConfig()), "CityActor");
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
System.out.println("Processing state " + message);
for (String aCity : getCitiesForState((String) message)) {
randomRouter.tell(aCity, getSelf());
}
Thread.sleep(1000);
}
}
public List<String> getCitiesForState(String stateName) {
return new ArrayList<String>(Arrays.asList("Springfield-" + stateName, "Salem-" + stateName,
"Franklin-" + stateName, "Clinton-" + stateName, "Georgetown-" + stateName));
};}
CityActor
public class CityActor extends UntypedActor {
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
System.out.println("Processing city " + message);
Thread.sleep(1000);
}
}}
Did i implement this use case properly?
I cannot get the code to terminate properly, i get dead letters messages. I know why i am getting them, but not sure how to properly implement it.
Any help is greatly appreciated.
Thanks
I tested and ran your use case with Akka 2.4.17. It works and terminate properly, without any dead letters logged.
Here are some remarks/suggestions to improve your understanding of the Akka toolkit:
Do not use Thread.sleep() inside an actor. Basically, it is never a good practice since a same thread may do many tasks for many actors (this is the default behavior with a shared thread pool). Instead, you can use an Akka scheduler or assign a single thread to a specific Actor (see this post for more details). See also the Akka documentation about that topic.
Having some dead letters is not always an issue. It generally arises when the system stops an Actor that had some messages within its mailbox. In this case, the remaining unprocessed messages are sent to deadLetters of the ActorSystem. I recommend you to check the configuration you provided for the logging of dead letters. If the file forum.conf you provided is your complete configuration file for Akka, you may want to customize some additional settings. See the page Logging of Dead Letters and Stopping actors on Akka's website. For instance, you could have a section like this:
akka {
# instead of System.out.println(conf);
log-config-on-start = on
# Max number of dead letters to log
log-dead-letters = 10
log-dead-letters-during-shutdown = on
}
Instead of using System.out.println() to log/debug, it is more convenient to set up a dedicated logger for each Actor that provides you additional information such as dispatchers, Actor name, etc. If your are interested, have a look to the Logging page.
Use some custom immutable message objects instead of systematic Strings. At first, it may seem painful to have to declare new additional classes but in the end it helps to better design complex behaviors and it's more readable. For instance, an actor A can answer to a RequestMsg coming from an actor B with an AnswerMsg or a custom ErrorMsg. Then, for your actor B, you will end up with the following onReceive() method:
#Override
public void onReceive(Object message) {
if (message instanceof AnswerMsg) {
// OK
AnswerMsg answerMsg = (AnswerMsg) message;
// ...
}
if (message instanceof ErrorMsg) {
// Not OK
ErrorMsg errorMsg = (ErrorMsg) message;
// ...
}
else {
// Unexpected behaviour, log it
log.error("Error, received " + message.toString() + " object.")
}
}
I hope that these resources will be useful for you.
Have a happy Akka programming! ;)
I'm trying to save a Location in a config.yml, and when he steps onto that location, it provokes an action. However, that is not happening.
Sorry for including the entire code, but I thought it would be essential for this kind of program.
Main class:
public class Turrets extends JavaPlugin{
ArrayList<String> playersThatShouldPlaceBlock = new ArrayList<String>();
HashMap<String, String> turretName = new HashMap<String, String>();
String turretsMsg = ChatColor.RED + "[" + ChatColor.GOLD + "Turrets" + ChatColor.RED + "]" + ChatColor.GOLD + ": ";
public int waitForPlacement;
public void loadConfig() {
this.getConfig().addDefault("Turrets.", null);
this.saveConfig();
}
public void onEnable(){
new CreateTurretEvent(this);
loadConfig();
}
public void onDisable(){
loadConfig();
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
final Player p = (Player) sender;
if (cmd.getName().equalsIgnoreCase("turret")){
if (args.length < 2){
p.sendMessage(turretsMsg + ChatColor.RED + "Invalid usage! /turret [create or delete] [name]");
return true;
}
else if (args.length >= 2){
if (args[0].equalsIgnoreCase("create")){
if (args[1] != null){
p.sendMessage(turretsMsg + ChatColor.GOLD + "Place a block and YOU will become a turret when you step on it!");
playersThatShouldPlaceBlock.add(p.getName());
turretName.put(p.getName(), args[1]);
waitForPlacement = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
#Override
public void run() {
p.sendMessage(turretsMsg + ChatColor.RED + "You waited too long so the action was cancelled!");
playersThatShouldPlaceBlock.remove(p.getName());
}
}, 600L);
return true;
}
}
}
}
return false;
}
}
Listener class:
package me.mortadelle2.turrets;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerMoveEvent;
public class CreateTurretEvent implements Listener{
Turrets getter;
public CreateTurretEvent(Turrets plugin){
plugin.getServer().getPluginManager().registerEvents(this, plugin);
getter = plugin;
}
#EventHandler
public void playerPlacesBlockToBecomeTurret(BlockPlaceEvent e){
Player p = e.getPlayer();
if (getter.playersThatShouldPlaceBlock.contains(p.getName())){
p.sendMessage(getter.turretsMsg + "That block is now turretified!");
getter.getServer().getScheduler().cancelTask(getter.waitForPlacement);
getter.playersThatShouldPlaceBlock.remove(p.getName());
Location blockLocation = e.getBlock().getLocation();
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName()), blockLocation);
}
}
#EventHandler
public void playerStepsOnTurret(PlayerMoveEvent e){
Player p = e.getPlayer();
if (getter.getConfig().contains("test")){ //I will add something more specific than test later
p.sendMessage("This is a test");
}
}
}
Problem 1: spelling mistake (this problem has been edited out of the question at question revision 3)
You seem to have misspelled onDisbale(){. When a plugin is disabled, it will run the method onDisable() on your plugin. In your case it isn't run because you don't have a method with that exact signature.
How to prevent this in the future
By added #Override at the start of a method, you are saying that it MUST override a existing method found in a parent class. This can be used like:
#Override
public void onDisable() {
Problem 2: Implementation of the PlayerMoveEvent isn't finished yet
Notice, stackoverflow isn't a "we write code for you service"
By analyzing your code, you are saving your config in the following format:
playername:
turretname: (location object)
Step 1: changing the location saving
The bukkit configuration doesn't work properly with Location objects, you should change your location saving to
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".world", player.getLocation().getWorld().getName());
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".x", player.getLocation().getBlockX());
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".y", player.getLocation().getBlockY());
getter.getConfig().set("Turrets." + getter.turretName.get(p.getName())+ ".z", player.getLocation().getBlockZ());
This changes the configuration to store the world, x, y and z seperately
Step 2: parsing the config at the PlayerMoveEvent
Because we changed our config format, it will be easier to detect what turret we are standing on at the PlayerMoveEvent
We will the following method of detecting what block we are standing on at the PlayerMove
Check if the turret exists inside the configuration
ConfigurationSection sec = getter.getConfig().getConfigurationSection("Turrets."+getter.turretName.get(p.getName()));
// Todo: check if the player exists inside getter.turretName
if(sec != null){
....
}
Parse the configuration to check if the location is found
Location loc = event.getPlayer().getLocation();
if(loc.getBlockX() == sec.getInt("x") && loc.getBlockY() == sec.getInt("y") && loc.getBlockZ() == sec.getInt("z") && loc.getWorld().getName().equals(sec.getString("world"))) {
event.getPlayer().sendMessage("This is a test");
}
This should fix the problem you are having. The following improvements can be done:
Only call the player move code when the player changes the block
Use more descriptive variable names, for example getter should be renamed to main or plugin
How can I override the test name that appears on the TestNG report? I want to override the name that appears in the middle column (currently shows as the method name). Is this even possible?
I tried to do it like this, but it didn't work.
public class EchApiTest1 extends TestBase {
...
#BeforeTest
public void setUp() {
restClient = new RestClientPost();
this.setTestName( "ech: XXXXXX" );
}
And, the base class:
import org.testng.ITest;
public class TestBase implements ITest {
String testName = "";
#Override
public String getTestName() {
return this.testName;
}
public void setTestName( String name ) {
this.testName = name;
}
}
NOTE: The above code does work when I am viewing the report detail in the Jenkins TestNG plugin report, which shows the overridden test name as a string called "Instance Name:" at the beginning of the Reporter log output. Why, in this case, WHY does a "setTestName()" method alter a string labeled "Instance Name" in the report?
One answer I found had a suggestion like this but I don't know how to pass an ITestResult arg to a AfterMethod method:
#AfterMethod
public void setResultTestName( ITestResult result ) {
try {
BaseTestMethod bm = (BaseTestMethod)result.getMethod();
Field f = bm.getClass().getSuperclass().getDeclaredField("m_methodName");
f.setAccessible(true);
f.set( bm, bm.getMethodName() + "." + your_customized_name );
} catch ( Exception ex ) {
Reporter.log( "ex" + ex.getMessage() );
}
Thoughts?
Please find following code for set custom name of testcase in TestNG reports.
Following features are available in this code.
Dynamic execution on same test-case in multiple time
Set custom test-case name for reports
Set parallel execution of multiple test-cases execution
import java.lang.reflect.Field;
import org.testng.ITest;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
import org.testng.internal.BaseTestMethod;
import com.test.data.ServiceProcessData;
public class ServiceTest implements ITest {
protected ServiceProcessData serviceProcessData;
protected String testCaseName = "";
#Test
public void executeServiceTest() {
System.out.println(this.serviceProcessData.toString());
}
#Factory(dataProvider = "processDataList")
public RiskServiceTest(ServiceProcessData serviceProcessData) {
this.serviceProcessData = serviceProcessData;
}
#DataProvider(name = "processDataList", parallel = true)
public static Object[] getProcessDataList() {
Object[] serviceProcessDataList = new Object[0];
//Set data in serviceProcessDataList
return serviceProcessDataList;
}
#Override
public String getTestName() {
this.testCaseName = "User custom testcase name";
// this.testCaseName = this.serviceProcessData.getTestCaseCustomName();
return this.testCaseName;
}
#AfterMethod(alwaysRun = true)
public void setResultTestName(ITestResult result) {
try {
BaseTestMethod baseTestMethod = (BaseTestMethod) result.getMethod();
Field f = baseTestMethod.getClass().getSuperclass().getDeclaredField("m_methodName");
f.setAccessible(true);
f.set(baseTestMethod, this.testCaseName);
} catch (Exception e) {
ErrorMessageHelper.getInstance().setErrorMessage(e);
Reporter.log("Exception : " + e.getMessage());
}
}}
Thanks
I found a "workaround" but I am hoping for a better answer. I want to be able to show this "test name" OR "instance name" value on the HTML report (not just within the Reporter.log output) and I am starting to think its not possible :
#Test(dataProvider = "restdata2")
public void testGetNameFromResponse( TestArguments testArgs ) {
this.setTestName( "ech: " + testArgs.getTestName() );
Reporter.log( getTestName() ); // this magic shows test name on report
....
With this workaround, the user can now identify which test it was by looking at the Reporter.log output but I still wish the name was more prominant.
I suspect the answer lies in writing a TestListenerAdapter that somehow overrides the ITestResult.getTestNameMethod() method? That is the holy grail I am looking for.
The ‘result’ object will automatically pass in the method setResultTestName( ITestResult result )
Make sure you put alwaysRun=true like the following when you have groups defined in your test class otherwise “AfterMethod” will not be excuted.
#AfterMethod (alwaysRun=true)
This seems like a simple thing to do but I can't seem to find any info anywhere! I've got a solution that has a service that we run in 'Console Mode' when debugging. I want it to be started and 'attached' when I run my unit test from Visual Studio.
I'm using Resharper as the unit test runner.
Not a direct answer to your question, BUT
We faced a similar problem recently and eventually settled on a solution using AppDomain
As your solution is already running as a Console project it would be little work to make it boot in a new AppDomain. Furthermore, you could run Assertions on this project as well as part of unit testing. (if required)
Consider the following static class Sandbox which you can use to boot multiple app domains.
The Execute method requires a Type which is-a SandboxAction. (class definition also included below)
You would first extend this class and provide any bootup actions for running your console project.
public class ConsoleRunnerProjectSandbox : SandboxAction
{
protected override void OnRun()
{
Bootstrapper.Start(); //this code will be run on the newly create app domain
}
}
Now to get your app domain running you simply call
Sandbox.Execute<ConsoleRunnerProjectSandbox>("AppDomainName", configFile)
Note you can pass this call a config file so you can bootup your project in the same fashion as if you were running it via the console
Any more questions please ask.
public static class Sandbox
{
private static readonly List<Tuple<AppDomain, SandboxAction>> _sandboxes = new List<Tuple<AppDomain, SandboxAction>>();
public static T Execute<T>(string friendlyName, string configFile, params object[] args)
where T : SandboxAction
{
Trace.WriteLine(string.Format("Sandboxing {0}: {1}", typeof (T).Name, configFile));
AppDomain sandbox = CreateDomain(friendlyName, configFile);
var objectHandle = sandbox.CreateInstance(typeof(T).Assembly.FullName, typeof(T).FullName, true, BindingFlags.Default, null, args, null, null, null);
T sandBoxAction = objectHandle.Unwrap() as T;
sandBoxAction.Run();
Tuple<AppDomain, SandboxAction> box = new Tuple<AppDomain, SandboxAction>(sandbox, sandBoxAction);
_sandboxes.Add(box);
return sandBoxAction;
}
private static AppDomain CreateDomain(string name, string customConfigFile)
{
FileInfo info = customConfigFile != null ? new FileInfo(customConfigFile) : null;
if (!string.IsNullOrEmpty(customConfigFile) && !info.Exists)
throw new ArgumentException("customConfigFile not found using " + customConfigFile + " at " + info.FullName);
var appsetup = new AppDomainSetup();
//appsetup.ApplicationBase = Path.GetDirectoryName(typeof(Sandbox).Assembly.Location);
appsetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
if (customConfigFile==null)
customConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
appsetup.ConfigurationFile = customConfigFile;
var sandbox = AppDomain.CreateDomain(
name,
AppDomain.CurrentDomain.Evidence,
appsetup);
return sandbox;
}
public static void DestroyAppDomainForSandbox(SandboxAction action)
{
foreach(var tuple in _sandboxes)
{
if(tuple.Second == action)
{
AppDomain.Unload(tuple.First);
Console.WriteLine("Unloaded sandbox ");
_sandboxes.Remove(tuple);
return;
}
}
}
}
[Serializable]
public abstract class SandboxAction : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null;
}
public void Run()
{
string name = AppDomain.CurrentDomain.FriendlyName;
Log.Info("Executing {0} in AppDomain:{1} thread:{2}", name, AppDomain.CurrentDomain.Id, Thread.CurrentThread.ManagedThreadId);
try
{
OnRun();
}
catch (Exception ex)
{
Log.Error(ex, "Exception in app domain {0}", name);
throw;
}
}
protected abstract void OnRun();
public virtual void Stop()
{
}
}