Skip to content

Commit

Permalink
[FAB-14490] Logging from chaincode
Browse files Browse the repository at this point in the history
Change-Id: Ibeb5119e468cf28492e517d9a5c785c1425c2134
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
Signed-off-by: James Taylor <jamest@uk.ibm.com>
  • Loading branch information
mbwhite committed Apr 26, 2019
1 parent 017d5c8 commit aba36b0
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 48 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ FABRIC_CFG_PATH=./sampleconfig .build/bin/configtxgen -outputCreateChannelTx sam

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

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

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

Install and instantiate the chaincode with the following commands.
Expand Down
2 changes: 1 addition & 1 deletion fabric-contract-api/lib/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function createLogger(level, name) {
module.exports.getLogger = function (name = '') {
// set the logging level based on the environment variable
// configured by the peer
const level = process.env.CORE_CHAINCODE_LOGGING_SHIM;
const level = process.env.CORE_CHAINCODE_LOGGING_LEVEL;
let loglevel = 'info';
if (typeof level === 'string') {
switch (level.toUpperCase()) {
Expand Down
18 changes: 9 additions & 9 deletions fabric-contract-api/test/unit/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ describe('Logger', () => {

let logLevel;
before(() => {
logLevel = process.env.CORE_CHAINCODE_LOGGING_SHIM;
logLevel = process.env.CORE_CHAINCODE_LOGGING_LEVEL;
});

after(() => {
process.env.CORE_CHAINCODE_LOGGING_SHIM = logLevel;
process.env.CORE_CHAINCODE_LOGGING_LEVEL = logLevel;
});

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

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

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

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

const log = Logger.getLogger();

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

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

const log = Logger.getLogger();

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

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

const log = Logger.getLogger();

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

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

const log = Logger.getLogger();

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

describe('formatter', () => {
it ('', () => {
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'DEBUG';
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'DEBUG';

const log = Logger.getLogger();
log.debug();
Expand All @@ -98,7 +98,7 @@ describe('Logger', () => {
});

it ('', () => {
process.env.CORE_CHAINCODE_LOGGING_SHIM = 'DEBUG';
process.env.CORE_CHAINCODE_LOGGING_LEVEL = 'DEBUG';

const log = Logger.getLogger('fred');
log.debug('hello', 'fred');
Expand Down
10 changes: 8 additions & 2 deletions fabric-contract-api/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@
SPDX-License-Identifier: Apache-2.0
*/
declare module 'fabric-contract-api' {

declare module 'fabric-contract-api' {
import { LoggerInstance } from 'winston';
import { ChaincodeStub, ClientIdentity } from 'fabric-shim';

export class Context {
stub: ChaincodeStub;
clientIdentity: ClientIdentity;
logger: {
setLevel: (level: string) => void,
getLogger: (name?: string) => LoggerInstance
}
}

export class Contract {
constructor(name?: string);

Expand Down
6 changes: 6 additions & 0 deletions fabric-shim/lib/contract-spi/chaincodefromcontract.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,12 @@ class ChaincodeFromContract {
const ctx = contractInstance.createContext();
ctx.setChaincodeStub(stub);
ctx.setClientIdentity(new ClientIdentity(stub));
ctx.logging = {
setLevel : Logger.setLevel,
getLogger : (name) => {
return Logger.getLogger(name ? `${cn}:${name}` : cn);
}
};

// get the specific information for this tx function
const functionExists = transactionDescriptor.transactions.find((transaction) => {
Expand Down
26 changes: 22 additions & 4 deletions fabric-shim/lib/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ function createLogger(level, name) {
return logger;
}

module.exports.getLogger = function (name = '') {
// set the logging level based on the environment variable
// configured by the peer
const level = process.env.CORE_CHAINCODE_LOGGING_SHIM;
const levelMapping = (level) => {
let loglevel = 'info';
if (typeof level === 'string') {
switch (level.toUpperCase()) {
Expand All @@ -51,10 +48,20 @@ module.exports.getLogger = function (name = '') {
break;
case 'DEBUG':
loglevel = 'debug';
break;
case 'INFO':
loglevel = 'info';
}
}
return loglevel;
};

module.exports.getLogger = function (name = '') {
// set the logging level based on the environment variable
// configured by the peer
const loglevel = levelMapping(process.env.CORE_CHAINCODE_LOGGING_LEVEL);
let logger;

if (loggers[name]) {
logger = loggers[name];
logger.level = loglevel;
Expand All @@ -65,3 +72,14 @@ module.exports.getLogger = function (name = '') {

return logger;
};

module.exports.setLevel = (level) => {
// set the level of all the loggers currently active
const loglevel = levelMapping(level);
process.env.CORE_CHAINCODE_LOGGING_LEVEL = loglevel;

Object.keys(loggers).forEach((name) => {
loggers[name].level = loglevel;
});
};

125 changes: 104 additions & 21 deletions fabric-shim/test/unit/contract-spi/chaincodefromcontract.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ chai.use(require('chai-things'));
const sinon = require('sinon');

const mockery = require('mockery');
const Logger = require('../../../lib/logger.js');


// standard utility fns
const path = require('path');
Expand Down Expand Up @@ -61,6 +63,22 @@ function log(...e) {
console.log(...e);
}

const certWithoutAttrs = '-----BEGIN CERTIFICATE-----' +
'MIICXTCCAgSgAwIBAgIUeLy6uQnq8wwyElU/jCKRYz3tJiQwCgYIKoZIzj0EAwIw' +
'eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' +
'biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT' +
'A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw' +
'OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp' +
'bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV' +
'BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa' +
'oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG' +
'1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E' +
'FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr' +
'TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI' +
'KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC' +
'IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN' +
'-----END CERTIFICATE-----';

describe('chaincodefromcontract', () => {

class MockDataMarhsall {
Expand Down Expand Up @@ -356,11 +374,11 @@ describe('chaincodefromcontract', () => {

beforeEach(() => {
fakeSuccess = sinon.fake((e) => {
sinon.assert.fail(e);
log(e);
});

fakeError = sinon.fake((e) => {
log(e);
sinon.assert.fail(e);
});

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

const mockStub = {getBufferArgs: sandbox.stub().returns([])};
cc.invokeFunctionality = sandbox.stub();
cc.Init(mockStub);
return cc.Init(mockStub);

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

const mockStub = {getBufferArgs: sandbox.stub().returns([Buffer.from('Hello')])};
cc.invokeFunctionality = sandbox.stub();
cc.Init(mockStub);
return cc.Init(mockStub);

});
});
Expand All @@ -427,9 +445,88 @@ describe('chaincodefromcontract', () => {
sinon.assert.calledOnce(_checkSuppliedStub);


const mockStub = {getBufferArgs: sandbox.stub().returns([Buffer.from('arg1'), Buffer.from('args2')])};
const mockStub = {getBufferArgs: sandbox.stub().returns([Buffer.from('arg1'), Buffer.from('args2')]),
getTxID: sandbox.stub().returns(12345)};
cc.invokeFunctionality = sandbox.stub();
cc.Invoke(mockStub);
return cc.Invoke(mockStub);

});

it('should pass the logging object to contracts', async () => {
const idBytes = {
toBuffer: () => {
return new Buffer(certWithoutAttrs);
}
};
const tempClass = class extends Contract {
constructor() {
super('logging');
}
/**
* @param {object} api api
* @param {String} arg1 arg1
* @param {String} arg2 arg2
*/
async alpha(ctx, arg1, arg2) {
return alphaStub(ctx, arg1, arg2);
}
};
const systemContract = new SystemContract();
const appClass = new tempClass();
sandbox.stub(ChaincodeFromContract.prototype, '_resolveContractImplementations')
.returns({
'org.hyperledger.fabric': {
contractInstance: systemContract
},
'logging':{
contractInstance: appClass,
transactions: [
{
name:'alpha'
}
],
dataMarshall:{
handleParameters: sandbox.stub().returns([]),
toWireBuffer: sandbox.stub()
}
}
});
sandbox.stub(ChaincodeFromContract.prototype, '_checkAgainstSuppliedMetadata').returns([]);
sandbox.stub(ChaincodeFromContract.prototype, '_compileSchemas');

const mockSigningId = {
getMspid: sinon.stub(),
getIdBytes: sinon.stub().returns(idBytes)
};
const cc = new ChaincodeFromContract([tempClass], defaultSerialization);
const mockStub = {getBufferArgs: sandbox.stub().returns(['logging:alpha']),
getTxID: sandbox.stub().returns('12345897asd7a7a77v7b77'),
getChannelID: sandbox.stub().returns('channel-id-fake'),
getCreator: sandbox.stub().returns(mockSigningId)
};
//
const levelSpy = sinon.spy(Logger, 'setLevel');
await cc.Invoke(mockStub);
const ctx = alphaStub.getCall(0).args[0];
ctx.logging.setLevel('DEBUG');
sinon.assert.called(levelSpy);
sinon.assert.calledWith(levelSpy, 'DEBUG');
const cclogger = ctx.logging.getLogger();
const logger = Logger.getLogger('logging');
const infospy = sinon.spy(logger, 'info');
cclogger.info('info');
sinon.assert.calledWith(infospy, 'info');

ctx.logging.setLevel('INFO');
sinon.assert.called(levelSpy);
sinon.assert.calledWith(levelSpy, 'INFO');


const ccloggerNamed = ctx.logging.getLogger('wibble');
const debugSpy = sinon.spy(Logger.getLogger('logging:wibble'), 'debug');
ccloggerNamed.debug('Named logger');
sinon.assert.calledWith(debugSpy, 'Named logger');


});
});
Expand Down Expand Up @@ -474,21 +571,7 @@ describe('chaincodefromcontract', () => {
let fakeSuccess;
let fakeError;

const certWithoutAttrs = '-----BEGIN CERTIFICATE-----' +
'MIICXTCCAgSgAwIBAgIUeLy6uQnq8wwyElU/jCKRYz3tJiQwCgYIKoZIzj0EAwIw' +
'eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' +
'biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT' +
'A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw' +
'OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp' +
'bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV' +
'BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa' +
'oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG' +
'1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E' +
'FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr' +
'TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI' +
'KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC' +
'IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN' +
'-----END CERTIFICATE-----';


beforeEach(() => {
fakeSuccess = sinon.fake((e) => {
Expand Down
Loading

0 comments on commit aba36b0

Please sign in to comment.