Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit c4910c0

Browse files
cr22rcjimthematrix
authored andcommitted
FAB-5312 Dump diagnostic files for logging.
Change-Id: Ib86f05755e10b1011921f495ae6abb43a8f878be Signed-off-by: rickr <cr22rc@gmail.com>
1 parent eb61de9 commit c4910c0

File tree

5 files changed

+265
-0
lines changed

5 files changed

+265
-0
lines changed

pom.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,26 @@
445445
</execution>
446446
</executions>
447447
</plugin>
448+
<plugin>
449+
<groupId>org.apache.maven.plugins</groupId>
450+
<artifactId>maven-antrun-plugin</artifactId>
451+
<version>1.4</version>
452+
<executions>
453+
<execution>
454+
<phase>generate-test-resources</phase>
455+
<configuration>
456+
<tasks>
457+
<echo message="Creating diagnostic dump output directory"/>
458+
<mkdir dir="./target/diagDump"/>
459+
</tasks>
460+
461+
</configuration>
462+
<goals>
463+
<goal>run</goal>
464+
</goals>
465+
</execution>
466+
</executions>
467+
</plugin>
448468
</plugins>
449469
</build>
450470
<distributionManagement>

src/main/java/org/hyperledger/fabric/sdk/Channel.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
import org.hyperledger.fabric.sdk.exception.TransactionEventException;
8888
import org.hyperledger.fabric.sdk.exception.TransactionException;
8989
import org.hyperledger.fabric.sdk.helper.Config;
90+
import org.hyperledger.fabric.sdk.helper.DiagnosticFileDumper;
9091
import org.hyperledger.fabric.sdk.helper.Utils;
9192
import org.hyperledger.fabric.sdk.transaction.InstallProposalBuilder;
9293
import org.hyperledger.fabric.sdk.transaction.InstantiateProposalBuilder;
@@ -115,7 +116,11 @@
115116
public class Channel {
116117
private static final Log logger = LogFactory.getLog(Channel.class);
117118
private static final boolean IS_DEBUG_LEVEL = logger.isDebugEnabled();
119+
private static final boolean IS_TRACE_LEVEL = logger.isTraceEnabled();
120+
118121
private static final Config config = Config.getConfig();
122+
private static final DiagnosticFileDumper diagnosticFileDumper = IS_TRACE_LEVEL
123+
? config.getDiagnosticFileDumper() : null;
119124
private static final String SYSTEM_CHANNEL_NAME = "";
120125

121126
// Name of the channel is only meaningful to the client
@@ -1981,6 +1986,13 @@ private Pair(Peer peer, Future<FabricProposalResponse.ProposalResponse> future)
19811986
for (Peer peer : peers) {
19821987
logger.debug(format("Channel %s send proposal to peer %s at url %s",
19831988
name, peer.getName(), peer.getUrl()));
1989+
1990+
if (null != diagnosticFileDumper) {
1991+
logger.trace(format("Sending to channel %s, peer: %s, proposal: %s", name, peer.getName(),
1992+
diagnosticFileDumper.createDiagnosticProtobufFile(signedProposal.toByteArray())));
1993+
1994+
}
1995+
19841996
Future<FabricProposalResponse.ProposalResponse> proposalResponseListenableFuture;
19851997
try {
19861998
proposalResponseListenableFuture = peer.sendProposalAsync(signedProposal);
@@ -2006,6 +2018,11 @@ private Pair(Peer peer, Future<FabricProposalResponse.ProposalResponse> future)
20062018
status = fabricResponse.getResponse().getStatus();
20072019
logger.debug(format("Channel %s got back from peer %s status: %d, message: %s",
20082020
name, peerName, status, message));
2021+
if (null != diagnosticFileDumper) {
2022+
logger.trace(format("Got back from channel %s, peer: %s, proposal response: %s", name, peerName,
2023+
diagnosticFileDumper.createDiagnosticProtobufFile(fabricResponse.toByteArray())));
2024+
2025+
}
20092026
} catch (InterruptedException e) {
20102027
message = "Sending proposal to " + peerName + " failed because of interruption";
20112028
logger.error(message, e);
@@ -2155,6 +2172,13 @@ public CompletableFuture<TransactionEvent> sendTransaction(Collection<ProposalRe
21552172
for (Orderer orderer : orderers) {
21562173

21572174
try {
2175+
2176+
if (null != diagnosticFileDumper) {
2177+
logger.trace(format("Sending to channel %s, orderer: %s, transaction: %s", name, orderer.getName(),
2178+
diagnosticFileDumper.createDiagnosticProtobufFile(transactionEnvelope.toByteArray())));
2179+
2180+
}
2181+
21582182
resp = orderer.sendTransaction(transactionEnvelope);
21592183
if (resp.getStatus() == Status.SUCCESS) {
21602184

src/main/java/org/hyperledger/fabric/sdk/helper/Config.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public class Config {
5454
public static final String MAX_LOG_STRING_LENGTH = "org.hyperledger.fabric.sdk.log.stringlengthmax";
5555
public static final String EXTRALOGLEVEL = "org.hyperledger.fabric.sdk.log.extraloglevel";
5656
public static final String LOGGERLEVEL = "org.hyperledger.fabric.sdk.loglevel"; // ORG_HYPERLEDGER_FABRIC_SDK_LOGLEVEL=TRACE,DEBUG
57+
public static final String DIAGNOTISTIC_FILE_DIRECTORY = "org.hyperledger.fabric.sdk.diagnosticFileDir"; //ORG_HYPERLEDGER_FABRIC_SDK_DIAGNOSTICFILEDIR
58+
5759

5860
private static Config config;
5961
private static final Properties sdkProperties = new Properties();
@@ -95,6 +97,8 @@ private Config() {
9597
defaultProperty(MAX_LOG_STRING_LENGTH, "64");
9698
defaultProperty(EXTRALOGLEVEL, "0");
9799
defaultProperty(LOGGERLEVEL, null);
100+
defaultProperty(DIAGNOTISTIC_FILE_DIRECTORY, null);
101+
98102

99103
final String inLogLevel = sdkProperties.getProperty(LOGGERLEVEL);
100104

@@ -290,4 +294,31 @@ public boolean extraLogLevel(int val) {
290294
return val <= extraLogLevel;
291295

292296
}
297+
298+
DiagnosticFileDumper diagnosticFileDumper = null;
299+
300+
/**
301+
* The directory where diagnostic dumps are to be place, null if none should be done.
302+
*
303+
* @return The directory where diagnostic dumps are to be place, null if none should be done.
304+
*/
305+
306+
public DiagnosticFileDumper getDiagnosticFileDumper() {
307+
308+
if (diagnosticFileDumper != null) {
309+
return diagnosticFileDumper;
310+
}
311+
312+
String dd = sdkProperties.getProperty(DIAGNOTISTIC_FILE_DIRECTORY);
313+
314+
if (dd != null) {
315+
316+
diagnosticFileDumper = DiagnosticFileDumper.configInstance(new File(dd));
317+
318+
}
319+
320+
return diagnosticFileDumper;
321+
}
322+
323+
293324
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
*
3+
* Copyright 2016,2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
*/
16+
17+
package org.hyperledger.fabric.sdk.helper;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.nio.ByteBuffer;
22+
import java.nio.channels.AsynchronousFileChannel;
23+
import java.nio.channels.CompletionHandler;
24+
import java.nio.file.Paths;
25+
import java.nio.file.StandardOpenOption;
26+
import java.text.SimpleDateFormat;
27+
import java.util.Date;
28+
import java.util.LinkedList;
29+
import java.util.TimeZone;
30+
import java.util.concurrent.BlockingQueue;
31+
import java.util.concurrent.LinkedBlockingQueue;
32+
import java.util.concurrent.atomic.AtomicInteger;
33+
34+
/**
35+
* Dumps files for diagnostic purposes
36+
*
37+
*/
38+
39+
public class DiagnosticFileDumper implements Runnable {
40+
41+
private final File directory;
42+
private final String dirAbsolutePath;
43+
private final String pid;
44+
// private static final Log logger = LogFactory.getLog(DiagnosticFileDumper.class);
45+
private static Thread thread;
46+
private final BlockingQueue<QueEntry> queEntries = new LinkedBlockingQueue<>();
47+
48+
private static DiagnosticFileDumper singleInstance = null;
49+
private static final AtomicInteger counter = new AtomicInteger(0);
50+
51+
private DiagnosticFileDumper(File directory) {
52+
53+
this.directory = directory;
54+
this.dirAbsolutePath = directory == null ? null : directory.getAbsolutePath();
55+
this.pid = getPID() + "";
56+
57+
}
58+
59+
static DiagnosticFileDumper configInstance(File directory) {
60+
61+
if (singleInstance == null) {
62+
singleInstance = new DiagnosticFileDumper(directory);
63+
thread = new Thread(singleInstance);
64+
thread.setName("DiagnosticFileDumper");
65+
thread.setDaemon(true);
66+
thread.start();
67+
68+
}
69+
70+
return singleInstance;
71+
72+
}
73+
74+
public String createDiagnosticProtobufFile(byte[] byteString) {
75+
76+
return createDiagnosticFile(byteString, "protobuf_", "proto");
77+
78+
}
79+
80+
private boolean cantWrite() {
81+
return null == directory || !directory.exists() || !directory.isDirectory() || !directory.canWrite();
82+
}
83+
84+
public String createDiagnosticFile(byte[] byteString, String prefix, String ext) {
85+
String fileName = "";
86+
if (cantWrite()) {
87+
return "Missing dump directory or can not write: " + (dirAbsolutePath);
88+
}
89+
if (null != byteString) {
90+
if (null == prefix) {
91+
prefix = "diagnostic_";
92+
}
93+
if (null == ext) {
94+
ext = "bin";
95+
}
96+
97+
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss_SSS");
98+
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
99+
fileName = prefix + dateFormatGmt.format(new Date()) + "P" + pid + "_" + Thread.currentThread().getId()
100+
+ "_" + counter.addAndGet(1) + "." + ext;
101+
fileName = fileName.replaceAll("\\:", "-"); // colon is bad for windows.
102+
103+
new QueEntry(fileName, byteString); //Add to Que let process by async thread.
104+
105+
}
106+
return fileName;
107+
108+
}
109+
110+
@Override
111+
public void run() {
112+
113+
while (true) {
114+
115+
try {
116+
final LinkedList<QueEntry> entries = new LinkedList<>();
117+
118+
entries.add(this.queEntries.take()); // wait on one.
119+
this.queEntries.drainTo(entries); //got one, see if there are more.
120+
121+
if (cantWrite()) {
122+
return; //IF the directory is missing just assume user does not want diagnostic files created anymore.
123+
}
124+
125+
entries.forEach(queEntry -> {
126+
127+
try {
128+
final AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get(dirAbsolutePath, queEntry.fileName),
129+
StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
130+
131+
channel.write(ByteBuffer.wrap(queEntry.dataBytes), 0, null, new CompletionHandler<Integer, Object>() {
132+
@Override
133+
public void completed(Integer result, Object attachment) {
134+
try {
135+
channel.close();
136+
} catch (IOException e) {
137+
//best effort
138+
}
139+
}
140+
141+
@Override
142+
public void failed(Throwable exc, Object attachment) {
143+
144+
try {
145+
channel.close();
146+
} catch (IOException e) {
147+
//best effort.
148+
}
149+
150+
}
151+
});
152+
153+
} catch (IOException e) {
154+
//best effort.
155+
}
156+
157+
});
158+
} catch (InterruptedException e) {
159+
// best effort
160+
}
161+
162+
}
163+
164+
}
165+
166+
class QueEntry {
167+
final String fileName;
168+
final byte[] dataBytes;
169+
170+
QueEntry(String fileName, byte[] dataBytes) {
171+
this.fileName = fileName;
172+
this.dataBytes = dataBytes;
173+
174+
queEntries.add(this);
175+
176+
}
177+
178+
}
179+
180+
private static long getPID() {
181+
String processName =
182+
java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
183+
return Long.parseLong(processName.split("@")[0]);
184+
}
185+
186+
}

src/test/cirun.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ cd $WD/src/test/fixture/sdkintegration
2121
./fabric.sh restart >dockerlogfile.log 2>&1 &
2222
cd $WD
2323
sleep 30
24+
docker images
2425
docker ps -a
26+
export ORG_HYPERLEDGER_FABRIC_SDK_DIAGNOSTICFILEDIR=target/diagDump
2527
mvn clean install -DskipITs=false -Dmaven.test.failure.ignore=false javadoc:javadoc
28+
docker images
29+
docker ps -a

0 commit comments

Comments
 (0)