I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications.
[App A] -> [App B] -> [App C]
We set a global id in the message header so we can trace each message lifecycle through the system.
I would like to be able to prepend any log message in the system with the message global id.
Has anyone else done this? Is there any way to associate this variable to the Thread so I can access it in future methods? I'd rather not pass the variable around in methods of the system.
I think ThreadLocal may be what you want here, though some may find this approach an abuse of ThreadLocal's purpose, or good design. Something like:
public class MyIDManager {
public static final ThreadLocal<Long> myID = new ThreadLocal<Long>();
}
...
// set ID at some point
MyIDManager.myID.set(theNewID);
...
// read it later
long currentID = MyIDManager.get();
The magic here is that myID's value is actually specific to a Thread, and will be different when accessed from different threads.
You can then do what you like with the ID, including logging it.
Thread t = Thread.currentThread();
t.setName("Your ID Here");
Another answer, which I believe the first post is alluding to, is to simply ask your logging framework to include the thread name in the log statement. For example, log4j lets you add the thread name with 't' in its PatternLayout: http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html I've seen this in other frameworks too.
BTW, this approach is part of a wider enterprise logging pattern. I attempted to document this pattern here. The summary is:
TL;DR
At the earliest inception of a ‘process’ create an ID which is a
combination of an ‘origin id’ and ‘unique id’. This non-business
related global inception ID (GIID), should be used for every log
output to provide machine readability and tool use. When each new
business level or operational id is obtained or generated, it is
logged to provide an ‘association’ with this GIID. This is similar to
various existing practices so it is presented as a Software Design
Pattern.
Related
I have many questions about the workflow ( sequence ) of interacting with the smart contract from Java application, so I will first explain what I have done and then put my questions, and if something wrong in my understanding please let me know.
1- I have written smart contract
2- Use truffle to get the smart contract java wrapper.(contract.java)
3- Use testrpc to test the contract
I have 2 class uses testrpc accounts (credentials) to interact with the smart contract and call its functions
Each class (node1.java, node2.java) call a function in the smart contract called (send) to send their data to the chain.
I have added an event which trigger if the 2 nodes have sent there data
What I don't understand is, how I can let the java code ( Let say MainProgram.class) always check for that event. Because I need to check if both nodes send their data, then I will call another function to analyse this data.
How I can manage, control and check what transactions have been done or not, I mean how I can use the events in java code and let the code run forever and check if the this event happen, do action.
Hope I can explain what I need clearly
Thank you in advance.
My answer to one of your previous questions applies here. Yes, you will probably want to setup a dedicated process to listen for events. But, you don't need an account or even be the owner or client of a smart contract to listen to events on the public blockchain (This is why it's considered "public").
To listen to events, all you need are the contract ABI and the contract's address. Both should be easy for you to get. You can set up a listener on all of the events this contract emits. From the web3j documentation:
You use the EthFilter type to specify the topics that you wish to apply to the filter. This can include the address of the smart contract you wish to apply the filter to. You can also provide specific topics to filter on. Where the individual topics represent indexed parameters on the smart contract:
EthFilter filter = new EthFilter(DefaultBlockParameterName.EARLIEST,
DefaultBlockParameterName.LATEST, <contract-address>)
[.addSingleTopic(...) | .addOptionalTopics(..., ...) | ...];
This filter can then be created using a similar syntax to the block and transaction filters above:
web3j.ethLogObservable(filter).subscribe(log -> {
...
});
Specifying the block parameters let you decide how far back in the history you want to start processing events. Keep in mind that in Ethereum, events are actually logs on the blockchain. When you listen for events, you're actually looking for activity in the logs as blocks are added to the chain. Therefore, you can go as far back in history as you want and look at older blocks to process old events as well.
To listen to all events in your contract, you would just do:
EthFilter filter = new EthFilter(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST, <CONTRACT_ADDRESS>);
web3.ethLogObservable(filter).subscribe(log -> System.out.println(log.toString());
IMPORTANT NOTE ON THE CONTRACT ADDRESS WITH ETHFILTER - There is a bug in Web3j for the contract address in EthFilter. The API doesn't like the leading '0x' in the contract address. To get around this, if you're using the contract object, send the contract address in using contract.getContractAddress().substring(2);
If you're interested in specific events, you need to add a topic to your filter. The example below will listen for all MyEvent events thrown which contains a single indexed address parameter and two non-indexed uint256 params:
Web3j web3j = Web3j.build(new HttpService());
Event event = new Event("MyEvent",
Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}),
Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}, new TypeReference<Uint256>() {}));
EthFilter filter = new EthFilter(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST, <CONTRACT_ADDRESS>);
filter.addSingleTopic(EventEncoder.encode(event));
web3j.ethLogObservable(filter).subscribe(log -> System.out.println(log.toString()));
The above can run in any server process. Within the server process, you can connect to the network either through a local node (the default localhost when using new HttpService()). Or, you can sign up with Infura, create an API key, and use and use their node cluster (example Ropsten URL: new HttpService("https://ropsten.infura.io/<YOUR_API_KEY>");)
As I understood that we have to use TransactionReceipt if we want to extract the events..
TransactionReceipt transactionReceipt = contract.someMethod(
<param1>,
...).send();
but what about for example if I have a function called "register" and need many accounts to register their self by invoking the function register.
how I can define accounts ( many credentials ) if the TransactionReceipt doesn't have parameters for ( from which account, gas limit, ..etc).
One more thing that I invoked the "register" function using TransactionReceipt as the following:
TransactionReceipt transactionReceipt = contract.register("John",BigInteger.valueOf(101)).send();
but this error appears:
Error processing transaction request: Error: Exceeds block gas limit
Thanks
As I understood that we have to use TransactionReceipt if we want to extract the events..
TransactionReceipt is not the only way to listen for events. You can also set up an Observable filter:
contract.someEventObservable(startBlock, endBlock).subscribe(event -> ...);
TransactionReceipt is a good way to get access to the events thrown for one specific transaction. All events thrown during the transaction are included in the receipt. However, if you want to process events in general across multiple transactions and/or use filters, you want to use an Observable filter. There's an entire section on event filters with examples here.
how I can define accounts ( many credentials ) if the TransactionReceipt doesn't have parameters for ( from which account, gas limit, ..etc).
If I'm understanding this question correctly, you want to know how to process the events section of the TransactionReceipt? Web3j provides a helper method in the contract instance which will process the logs from TransactionReceipt.
EventValues eventValues = contract.processEVENT_NAMEEvent(transactionReceipt);
Replace EVENT_NAME with the event type you're interested in. Any account specific information you need to identify the event you want (address, name, etc) should be included in the event itself.
EDIT: Based on your comment, it looks like I misunderstood this part of your question. I'll leave my previous answer here in case it's useful for processing events and address your question below.
After you create your contract instance (either through deploy or load), you can change the gas limit and gas price. Both have setters in the wrapper's parent class. Therefore, you can reuse the same wrapper to call different functions in your contract using the appropriate gas parameters for that particular function.
However, you cannot change the underlying Credentials (at least, not without subclassing or changing the generated wrapper). For different credentials, create different wrapper objects using .load.
but this error appears:
Error processing transaction request: Error: Exceeds block gas limit
I can't help with this without seeing the contract and code used to call the function.
When we add logs in to the java class (using log4j), Is it fine to add thread id with that log messages? is it a bad practice? My idea was to add this thread id; Once we examine a log file of a multithreaded application, it is difficult to find out the correct flow using logs. (As an example, say authentication flow). Is there any better approach for this rather than logging thread id?
Log4j already supports the thread name using t placeholder in its pattern layout. So this is a supported feature that you should use if you find it useful. This way you don't need to pass the thread name manually. However it doesn't make use of the thread ID. So you should give meaningful names to your threads. This should be preferred as it is more indicative to what is going on in your application than just plain thread ids.
If it is the thread id, please refer this answer
However if you only need the thread name, you can use the t pattern configuration, please refer here.
If you are using Java Logger API - LogRecord has method getThreadID() and can be configured to log.
For log4j there are no ThreadId methods available and No harm in logging it.
In cases If your class inherits from Thread, you can use methods getName and setName to name each thread. Otherwise you could just add a name field to MyTask, and initialize it in your constructor And use a more sensible Thread Name instead of ID.
Logback has a special appender called SiftingAppender which provides a very nice solution to the type of problems you describe. A SiftingAppender can be used to separate (or sift) logging according to any runtime attribute, including thread id
If your concern is about several JVMs writing to the same FileAppender, then i'd suggest two things:
using SLF4J as a logging facade
using logback as logging implementation, in prudent mode
In prudent mode, FileAppender will safely write to the specified
file, even in the presence of other FileAppender instances running in
different JVMs, potentially running on different hosts.
Refer this: http://logback.qos.ch/manual/appenders.html#SiftingAppender
i wrote a own Security Manager and my problem is, that i run code from other users in my program, and i have to ensure that there is no abuse.
So my Question is: How i am able to find out in the Methods of the Security Manager , who asks for the Access in the checkXXXXX() - methods.
Thanks
No there is no simple way to do this in the general case.
(If you were running within a web container, that might provide a way to get hold of the current request's authentication details. But that doesn't sound like your use-case.)
I guess there are a variety of ways that you could attempt to implement this, though you'd need to be careful to protect against code that spoofs the user identity. One idea is to associate each user identity with a distinct ThreadGroup, and get your security manager to block creation of threads in other thread groups; read the javadoc for Thread(ThreadGroup group, Runnable target, String name), paying attention to what it says about the thread group check.
I have a layered application in Java which has a multi thread data access layer which is invoked from different points. A single call to this layer is likely to spawn several threads to parallelize requests to the DB.
What I'm looking for is a logging tool that would allow me to define "activities" that are composed by various threads. Therefore, the same method in the data access layer should log different outputs depending on its caller. The ability to group different outputs to summarize the total cost of an operation is also important.
Although the application is in Java, language is not a restriction; what I need are the design guidelines so to eventually implement it. We are currently using log4j, but can't get this behaviour from it.
You should also have a look at the nested diagnostic context feature of log4j. Pushing different contexts to the logger for different callers might do the trick for you.
You should be able to pass a logger around, so you create a logger based on some "common" for the task data - i.e. username, etc. Then, pass this logger as parameter to all methods you need. That way, you'll be able to set different filters and/or rules in your log4j config file. Or to scrape the output file based on the logger name.
EDIT: Also check MDC and NDC classes in log4j. You can add there context data.
In log4j you can log the thread name with the "%t" pattern. See log4j Pattern Layout.
In one of my (web) applications, i use a ThreadLocal logger that captures logging information into a StringBuilder. The logger object is initialized in the HttpServlet#service method, if a trace parameter is set (if it is not set, there is a very fast null-logger). The resulting output is either dumped as a HTML comment into the requesting page, or written to a log file in one segment.
In Java5 (and later) you can call
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
Inspect the stack trace to whatever depth you want and log accordingly.
In Java 1.4 you can get the same info with
StackTraceElement[] stackTrace = new Exception().getStackTrace();
You want to associate logger objects with threads I think. A ThreadLocal variable holding a log4j logger instance for each thread might help:
http://java.sun.com/javase/6/docs/api/java/lang/ThreadLocal.html
You will need to pass some structure to the data access layer that identifies the current "activity". You might already have an "Activity"-class that makes sense, you might use a Logger-instance as Sunny suggested or you might use a third structure to keep track of the activity-context.
In any case, since your "activity" is processed across multiple threads you cannot use thread-local-storage for keeping track of the current "activity", like most of the other current answers suggest. You will need to pass it around explicitly.
I would suggest making a small facade on top of log4j that expands the interface with methods like
void debug(Activity activity, String message);
and passing the activity-context into this from the data access layer.
You will need to make some modification to the data access layer to allow you to pass the current activity to it, but how best to do that depends strongly on the current interface.
If you use the Workspace-pattern, you might just need to add a setActivity() method on the Workspace-class, but other interface-pattern might require you to add an Activity parameter to all methods.
If you for some reason is unable or unwilling to change the data access layer, you might of course store the activity-context in thread-local-storage before invoking the data access layer and retrieve it just before spawning the sub-threads or enqueing the jobs in the data access layer. That is a workable solution, but is it a bit dangerous to pass information around in that way.
You can use MDC or NDC for your scenario, NDC works on principle of stack while MDC works on Map, here is official documentation for both
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/NDC.html