Skip to content

Commit aba36b0

Browse files
committed
[FAB-14490] Logging from chaincode
Change-Id: Ibeb5119e468cf28492e517d9a5c785c1425c2134 Signed-off-by: Matthew B. White <whitemat@uk.ibm.com> Signed-off-by: James Taylor <jamest@uk.ibm.com>
1 parent 017d5c8 commit aba36b0

9 files changed

Lines changed: 182 additions & 48 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ FABRIC_CFG_PATH=./sampleconfig .build/bin/configtxgen -outputCreateChannelTx sam
117117

118118
Then you can launch a peer node with the following commands:
119119
```
120-
FABRIC_CFG_PATH=./sampleconfig CORE_CHAINCODE_LOGGING_SHIM=debug FABRIC_LOGGING_SPEC=debug CORE_PEER_ADDRESSAUTODETECT=true .build/bin/peer node start --peer-chaincodedev
120+
FABRIC_CFG_PATH=./sampleconfig CORE_CHAINCODE_LOGGING_LEVEL=debug FABRIC_LOGGING_SPEC=debug CORE_PEER_ADDRESSAUTODETECT=true .build/bin/peer node start --peer-chaincodedev
121121
```
122122

123123
Then you can launch an orderer node with the following commands:
@@ -353,7 +353,7 @@ rm -r /var/hyperledger/production
353353

354354
When launching a peer node, eliminate the `--peer-chaincodev` program argument to start the peer process in network mode.
355355
```
356-
FABRIC_CFG_PATH=./sampleconfig CORE_CHAINCODE_LOGGING_SHIM=debug FABRIC_LOGGING_SPEC=debug CORE_PEER_ADDRESSAUTODETECT=true .build/bin/peer node start
356+
FABRIC_CFG_PATH=./sampleconfig CORE_CHAINCODE_LOGGING_LEVEL=debug FABRIC_LOGGING_SPEC=debug CORE_PEER_ADDRESSAUTODETECT=true .build/bin/peer node start
357357
```
358358

359359
Install and instantiate the chaincode with the following commands.

fabric-contract-api/lib/logger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function createLogger(level, name) {
3636
module.exports.getLogger = function (name = '') {
3737
// set the logging level based on the environment variable
3838
// configured by the peer
39-
const level = process.env.CORE_CHAINCODE_LOGGING_SHIM;
39+
const level = process.env.CORE_CHAINCODE_LOGGING_LEVEL;
4040
let loglevel = 'info';
4141
if (typeof level === 'string') {
4242
switch (level.toUpperCase()) {

fabric-contract-api/test/unit/logger.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ describe('Logger', () => {
1818

1919
let logLevel;
2020
before(() => {
21-
logLevel = process.env.CORE_CHAINCODE_LOGGING_SHIM;
21+
logLevel = process.env.CORE_CHAINCODE_LOGGING_LEVEL;
2222
});
2323

2424
after(() => {
25-
process.env.CORE_CHAINCODE_LOGGING_SHIM = logLevel;
25+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = logLevel;
2626
});
2727

2828
it ('should create a new logger name unknown', () => {
29-
process.env.CORE_CHAINCODE_LOGGING_SHIM = null;
29+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = null;
3030

3131
const log = Logger.getLogger('unknown name');
3232

@@ -50,7 +50,7 @@ describe('Logger', () => {
5050
});
5151

5252
it ('should set the log level to fatal when env var set to CRITICAL', () => {
53-
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'CRITICAL';
53+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'CRITICAL';
5454

5555
const log = Logger.getLogger();
5656

@@ -59,7 +59,7 @@ describe('Logger', () => {
5959
});
6060

6161
it ('should set the log level to error when env var set to ERROR', () => {
62-
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'ERROR';
62+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'ERROR';
6363

6464
const log = Logger.getLogger();
6565

@@ -68,7 +68,7 @@ describe('Logger', () => {
6868
});
6969

7070
it ('should set the log level to warn when env var set to WARNING', () => {
71-
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'WARNING';
71+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'WARNING';
7272

7373
const log = Logger.getLogger();
7474

@@ -77,7 +77,7 @@ describe('Logger', () => {
7777
});
7878

7979
it ('should set the log level to debug when env var set to DEBUG', () => {
80-
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'DEBUG';
80+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'DEBUG';
8181

8282
const log = Logger.getLogger();
8383

@@ -88,7 +88,7 @@ describe('Logger', () => {
8888

8989
describe('formatter', () => {
9090
it ('', () => {
91-
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'DEBUG';
91+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'DEBUG';
9292

9393
const log = Logger.getLogger();
9494
log.debug();
@@ -98,7 +98,7 @@ describe('Logger', () => {
9898
});
9999

100100
it ('', () => {
101-
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'DEBUG';
101+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'DEBUG';
102102

103103
const log = Logger.getLogger('fred');
104104
log.debug('hello', 'fred');

fabric-contract-api/types/index.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@
44
SPDX-License-Identifier: Apache-2.0
55
66
*/
7-
declare module 'fabric-contract-api' {
87

8+
declare module 'fabric-contract-api' {
9+
import { LoggerInstance } from 'winston';
910
import { ChaincodeStub, ClientIdentity } from 'fabric-shim';
11+
1012
export class Context {
1113
stub: ChaincodeStub;
1214
clientIdentity: ClientIdentity;
15+
logger: {
16+
setLevel: (level: string) => void,
17+
getLogger: (name?: string) => LoggerInstance
18+
}
1319
}
14-
20+
1521
export class Contract {
1622
constructor(name?: string);
1723

fabric-shim/lib/contract-spi/chaincodefromcontract.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,12 @@ class ChaincodeFromContract {
316316
const ctx = contractInstance.createContext();
317317
ctx.setChaincodeStub(stub);
318318
ctx.setClientIdentity(new ClientIdentity(stub));
319+
ctx.logging = {
320+
setLevel : Logger.setLevel,
321+
getLogger : (name) => {
322+
return Logger.getLogger(name ? `${cn}:${name}` : cn);
323+
}
324+
};
319325

320326
// get the specific information for this tx function
321327
const functionExists = transactionDescriptor.transactions.find((transaction) => {

fabric-shim/lib/logger.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ function createLogger(level, name) {
3333
return logger;
3434
}
3535

36-
module.exports.getLogger = function (name = '') {
37-
// set the logging level based on the environment variable
38-
// configured by the peer
39-
const level = process.env.CORE_CHAINCODE_LOGGING_SHIM;
36+
const levelMapping = (level) => {
4037
let loglevel = 'info';
4138
if (typeof level === 'string') {
4239
switch (level.toUpperCase()) {
@@ -51,10 +48,20 @@ module.exports.getLogger = function (name = '') {
5148
break;
5249
case 'DEBUG':
5350
loglevel = 'debug';
51+
break;
52+
case 'INFO':
53+
loglevel = 'info';
5454
}
5555
}
56+
return loglevel;
57+
};
5658

59+
module.exports.getLogger = function (name = '') {
60+
// set the logging level based on the environment variable
61+
// configured by the peer
62+
const loglevel = levelMapping(process.env.CORE_CHAINCODE_LOGGING_LEVEL);
5763
let logger;
64+
5865
if (loggers[name]) {
5966
logger = loggers[name];
6067
logger.level = loglevel;
@@ -65,3 +72,14 @@ module.exports.getLogger = function (name = '') {
6572

6673
return logger;
6774
};
75+
76+
module.exports.setLevel = (level) => {
77+
// set the level of all the loggers currently active
78+
const loglevel = levelMapping(level);
79+
process.env.CORE_CHAINCODE_LOGGING_LEVEL = loglevel;
80+
81+
Object.keys(loggers).forEach((name) => {
82+
loggers[name].level = loglevel;
83+
});
84+
};
85+

fabric-shim/test/unit/contract-spi/chaincodefromcontract.js

Lines changed: 104 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ chai.use(require('chai-things'));
2323
const sinon = require('sinon');
2424

2525
const mockery = require('mockery');
26+
const Logger = require('../../../lib/logger.js');
27+
2628

2729
// standard utility fns
2830
const path = require('path');
@@ -61,6 +63,22 @@ function log(...e) {
6163
console.log(...e);
6264
}
6365

66+
const certWithoutAttrs = '-----BEGIN CERTIFICATE-----' +
67+
'MIICXTCCAgSgAwIBAgIUeLy6uQnq8wwyElU/jCKRYz3tJiQwCgYIKoZIzj0EAwIw' +
68+
'eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' +
69+
'biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT' +
70+
'A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw' +
71+
'OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp' +
72+
'bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV' +
73+
'BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa' +
74+
'oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG' +
75+
'1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E' +
76+
'FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr' +
77+
'TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI' +
78+
'KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC' +
79+
'IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN' +
80+
'-----END CERTIFICATE-----';
81+
6482
describe('chaincodefromcontract', () => {
6583

6684
class MockDataMarhsall {
@@ -356,11 +374,11 @@ describe('chaincodefromcontract', () => {
356374

357375
beforeEach(() => {
358376
fakeSuccess = sinon.fake((e) => {
359-
sinon.assert.fail(e);
377+
log(e);
360378
});
361379

362380
fakeError = sinon.fake((e) => {
363-
log(e);
381+
sinon.assert.fail(e);
364382
});
365383

366384
sandbox.replace(shim, 'success', fakeSuccess);
@@ -384,7 +402,7 @@ describe('chaincodefromcontract', () => {
384402

385403
const mockStub = {getBufferArgs: sandbox.stub().returns([])};
386404
cc.invokeFunctionality = sandbox.stub();
387-
cc.Init(mockStub);
405+
return cc.Init(mockStub);
388406

389407
});
390408
it('should handle a single class being passed as a contract', () => {
@@ -405,7 +423,7 @@ describe('chaincodefromcontract', () => {
405423

406424
const mockStub = {getBufferArgs: sandbox.stub().returns([Buffer.from('Hello')])};
407425
cc.invokeFunctionality = sandbox.stub();
408-
cc.Init(mockStub);
426+
return cc.Init(mockStub);
409427

410428
});
411429
});
@@ -427,9 +445,88 @@ describe('chaincodefromcontract', () => {
427445
sinon.assert.calledOnce(_checkSuppliedStub);
428446

429447

430-
const mockStub = {getBufferArgs: sandbox.stub().returns([Buffer.from('arg1'), Buffer.from('args2')])};
448+
const mockStub = {getBufferArgs: sandbox.stub().returns([Buffer.from('arg1'), Buffer.from('args2')]),
449+
getTxID: sandbox.stub().returns(12345)};
431450
cc.invokeFunctionality = sandbox.stub();
432-
cc.Invoke(mockStub);
451+
return cc.Invoke(mockStub);
452+
453+
});
454+
455+
it('should pass the logging object to contracts', async () => {
456+
const idBytes = {
457+
toBuffer: () => {
458+
return new Buffer(certWithoutAttrs);
459+
}
460+
};
461+
const tempClass = class extends Contract {
462+
constructor() {
463+
super('logging');
464+
}
465+
/**
466+
* @param {object} api api
467+
* @param {String} arg1 arg1
468+
* @param {String} arg2 arg2
469+
*/
470+
async alpha(ctx, arg1, arg2) {
471+
return alphaStub(ctx, arg1, arg2);
472+
}
473+
};
474+
const systemContract = new SystemContract();
475+
const appClass = new tempClass();
476+
sandbox.stub(ChaincodeFromContract.prototype, '_resolveContractImplementations')
477+
.returns({
478+
'org.hyperledger.fabric': {
479+
contractInstance: systemContract
480+
},
481+
'logging':{
482+
contractInstance: appClass,
483+
transactions: [
484+
{
485+
name:'alpha'
486+
}
487+
],
488+
dataMarshall:{
489+
handleParameters: sandbox.stub().returns([]),
490+
toWireBuffer: sandbox.stub()
491+
}
492+
}
493+
});
494+
sandbox.stub(ChaincodeFromContract.prototype, '_checkAgainstSuppliedMetadata').returns([]);
495+
sandbox.stub(ChaincodeFromContract.prototype, '_compileSchemas');
496+
497+
const mockSigningId = {
498+
getMspid: sinon.stub(),
499+
getIdBytes: sinon.stub().returns(idBytes)
500+
};
501+
const cc = new ChaincodeFromContract([tempClass], defaultSerialization);
502+
const mockStub = {getBufferArgs: sandbox.stub().returns(['logging:alpha']),
503+
getTxID: sandbox.stub().returns('12345897asd7a7a77v7b77'),
504+
getChannelID: sandbox.stub().returns('channel-id-fake'),
505+
getCreator: sandbox.stub().returns(mockSigningId)
506+
};
507+
//
508+
const levelSpy = sinon.spy(Logger, 'setLevel');
509+
await cc.Invoke(mockStub);
510+
const ctx = alphaStub.getCall(0).args[0];
511+
ctx.logging.setLevel('DEBUG');
512+
sinon.assert.called(levelSpy);
513+
sinon.assert.calledWith(levelSpy, 'DEBUG');
514+
const cclogger = ctx.logging.getLogger();
515+
const logger = Logger.getLogger('logging');
516+
const infospy = sinon.spy(logger, 'info');
517+
cclogger.info('info');
518+
sinon.assert.calledWith(infospy, 'info');
519+
520+
ctx.logging.setLevel('INFO');
521+
sinon.assert.called(levelSpy);
522+
sinon.assert.calledWith(levelSpy, 'INFO');
523+
524+
525+
const ccloggerNamed = ctx.logging.getLogger('wibble');
526+
const debugSpy = sinon.spy(Logger.getLogger('logging:wibble'), 'debug');
527+
ccloggerNamed.debug('Named logger');
528+
sinon.assert.calledWith(debugSpy, 'Named logger');
529+
433530

434531
});
435532
});
@@ -474,21 +571,7 @@ describe('chaincodefromcontract', () => {
474571
let fakeSuccess;
475572
let fakeError;
476573

477-
const certWithoutAttrs = '-----BEGIN CERTIFICATE-----' +
478-
'MIICXTCCAgSgAwIBAgIUeLy6uQnq8wwyElU/jCKRYz3tJiQwCgYIKoZIzj0EAwIw' +
479-
'eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' +
480-
'biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT' +
481-
'A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw' +
482-
'OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp' +
483-
'bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV' +
484-
'BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa' +
485-
'oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG' +
486-
'1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E' +
487-
'FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr' +
488-
'TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI' +
489-
'KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC' +
490-
'IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN' +
491-
'-----END CERTIFICATE-----';
574+
492575

493576
beforeEach(() => {
494577
fakeSuccess = sinon.fake((e) => {

0 commit comments

Comments
 (0)