|
| 1 | +# Logging CorDapp |
| 2 | + |
| 3 | +## Custom Logging |
| 4 | + |
| 5 | +This is a modified version of the original yo cordapp with some additions to use custom log4j2 configurations. |
| 6 | + |
| 7 | + |
| 8 | +The primary example we've implemented here is json logging which is configured in `config/dev/log4j2.xml`. |
| 9 | + |
| 10 | +This gives us the ability to use Log4j thread contexts to log arbitrary objects or data points in json format. |
| 11 | + |
| 12 | +In this example not only do the node logs output in json but we can add arbitrary key value pairs as well. |
| 13 | + |
| 14 | +```java |
| 15 | + // here we have our first opportunity to log out the contents of the flow arguments. |
| 16 | + ThreadContext.put("initiator", me.name.toString()) |
| 17 | + ThreadContext.put("target", target.name.toString()) |
| 18 | + // publish to the log with the additional context |
| 19 | + logger.info("Initializing the transaction.") |
| 20 | +``` |
| 21 | + |
| 22 | +When we log this message, it gets output along with the other key value pairs we've specified in a JSON format: |
| 23 | +``` |
| 24 | +{ |
| 25 | + "instant": { |
| 26 | + "epochSecond": 1612982209, |
| 27 | + "nanoOfSecond": 487000000 |
| 28 | + }, |
| 29 | + "thread": "Node thread-1", |
| 30 | + "level": "INFO", |
| 31 | + "loggerName": "net.corda", |
| 32 | + "message": "Initializing the transaction.", |
| 33 | + "endOfBatch": true, |
| 34 | + "loggerFqcn": "org.apache.logging.slf4j.Log4jLogger", |
| 35 | + "contextMap": { |
| 36 | + "actor_id": "internalShell", |
| 37 | + "actor_owning_identity": "O=PartyA, L=London, C=GB", |
| 38 | + "actor_store_id": "NODE_CONFIG", |
| 39 | + "fiber-id": "10000001", |
| 40 | + "flow-id": "94543b19-b949-441e-9962-bc50dcd7ad55", |
| 41 | + "initiator": "O=PartyA, L=London, C=GB", |
| 42 | + "invocation_id": "a53a3a5d-b450-456e-a0f1-dfb7dcdce6dd", |
| 43 | + "invocation_timestamp": "2021-02-10T18:36:49.312Z", |
| 44 | + "origin": "internalShell", |
| 45 | + "session_id": "e8ba737e-e809-4a14-8c3b-284b7ae5ed88", |
| 46 | + "session_timestamp": "2021-02-10T18:36:49.022Z", |
| 47 | + "target": "O=PartyB, L=New York, C=US", |
| 48 | + "thread-id": "168" |
| 49 | + }, |
| 50 | + "threadId": 168, |
| 51 | + "threadPriority": 5 |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | + |
| 56 | +This can be quite powerful if you're looking to produce a consumable output stream to a log aggregator like splunk. |
| 57 | + |
| 58 | +You can end up getting log feeds in json that look something like this: |
| 59 | + |
| 60 | +```json |
| 61 | +{"instant":{"epochSecond":1612369055,"nanoOfSecond":12000000},"thread":"main","level":"INFO","loggerName":"net.corda.node.internal.Node","message":"Vendor: Corda Open Source","endOfBatch":true,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":1,"threadPriority":5} |
| 62 | +. . .More Node Startup loggings |
| 63 | + |
| 64 | +// when our flow is run we see the log we specified |
| 65 | +{"instant":{"epochSecond":1612460471,"nanoOfSecond":866000000},"thread":"pool-10-thread-2","level":"INFO","loggerName":"net.corda.tools.shell.FlowShellCommand","message":"Executing command \"flow start net.corda.samples.logging.flows.YoFlow target: PartyA\",","endOfBatch":true,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":224,"threadPriority":5} |
| 66 | +{"instant":{"epochSecond":1612460472,"nanoOfSecond":304000000},"thread":"Node thread-1","level":"INFO","loggerName":"net.corda","message":"Initializing the transaction.","endOfBatch":true,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":166,"threadPriority":5} |
| 67 | +{"instant":{"epochSecond":1612460472,"nanoOfSecond":428000000},"thread":"pool-10-thread-2","level":"WARN","loggerName":"net.corda.tools.shell.utlities.StdoutANSIProgressRenderer","message":"Cannot find console appender - progre |
| 68 | +``` |
| 69 | + |
| 70 | +## Usage |
| 71 | + |
| 72 | + |
| 73 | +### Pre-Requisites |
| 74 | + |
| 75 | +See https://docs.corda.net/getting-set-up.html. |
| 76 | + |
| 77 | + |
| 78 | +### Running the CorDapp |
| 79 | + |
| 80 | +Open a terminal and go to the project root directory and type: (to deploy the nodes using bootstrapper) |
| 81 | +``` |
| 82 | +./gradlew clean deployNodes |
| 83 | +``` |
| 84 | +Then type: (to run the nodes) |
| 85 | + |
| 86 | +``` |
| 87 | +./build/nodes/runnodes |
| 88 | +``` |
| 89 | + |
| 90 | +When the nodes run you'll be able to see the node's json log files in their respesctive `logs` folders. |
| 91 | +This logging configuration will add a new file that you can view. |
| 92 | + |
| 93 | +```shell |
| 94 | +tail -f build/nodes/PartyA/logs/node.json |
| 95 | + |
| 96 | +{"instant":{"epochSecond":1612543764,"nanoOfSecond":930000000},"thread":"main","level":"INFO","loggerName":"net.corda.cliutils.CliWrapperBase","message":"Application Args: run-migration-scripts --core-schemas --app-schemas","endOfBatch":true,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","contextMap":{},"threadId":1,"threadPriority":5} |
| 97 | +{"instant":{"epochSecond":1612543766,"nanoOfSecond":300000000} |
| 98 | + |
| 99 | +. . . |
| 100 | +``` |
| 101 | + |
| 102 | +### Sending a Yo |
| 103 | + |
| 104 | +We will interact with the nodes via their specific shells. When the nodes are up and running, use the following command to send a |
| 105 | +Yo to another node: |
| 106 | + |
| 107 | +``` |
| 108 | + flow start YoFlow target: PartyB |
| 109 | +``` |
| 110 | + |
| 111 | +Where `NODE_NAME` is 'PartyA' or 'PartyB'. The space after the `:` is required. You are not required to use the full |
| 112 | +X500 name in the node shell. Note you can't sent a Yo! to yourself because that's not cool! |
| 113 | + |
| 114 | +To see all the Yo's! other nodes have sent you in your vault (you do not store the Yo's! you send yourself), run: |
| 115 | + |
| 116 | +``` |
| 117 | + run vaultQuery contractStateType: YoState |
| 118 | +``` |
| 119 | + |
| 120 | +### Other ways to use this log configuration |
| 121 | + |
| 122 | +The above method will run all nodes together but if you're running your corda node manually all you need to do is specify the particular config file. |
| 123 | + |
| 124 | +You can do that by just running the jar directly: |
| 125 | + |
| 126 | +```shell |
| 127 | +java -Dlog4j.configurationFile=logging-cordapp/build/resources/main/log4j2.xml -jar corda.jar |
| 128 | +``` |
| 129 | + |
| 130 | +> notice that all we're doing is adding this param to the command we'd otherwise use to run corda in order to specify the log file. |
| 131 | + |
| 132 | + |
| 133 | +## Attribution |
| 134 | + |
| 135 | +This example was built with help from [Splunk](https://splunk.com), and they have our thanks. |
| 136 | + |
0 commit comments