github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/chaincode/shim/chaincode.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package shim provides APIs for the chaincode to access its state 18 // variables, transaction context and call other chaincodes. 19 package shim 20 21 import ( 22 "errors" 23 "flag" 24 "fmt" 25 "io" 26 "os" 27 "strings" 28 "unicode/utf8" 29 30 "github.com/golang/protobuf/proto" 31 "github.com/golang/protobuf/ptypes/timestamp" 32 "github.com/hyperledger/fabric/bccsp/factory" 33 "github.com/hyperledger/fabric/core/comm" 34 pb "github.com/hyperledger/fabric/protos/peer" 35 "github.com/hyperledger/fabric/protos/utils" 36 "github.com/op/go-logging" 37 "github.com/spf13/viper" 38 "golang.org/x/net/context" 39 "google.golang.org/grpc" 40 ) 41 42 // Logger for the shim package. 43 var chaincodeLogger = logging.MustGetLogger("shim") 44 45 const ( 46 minUnicodeRuneValue = 0 //U+0000 47 maxUnicodeRuneValue = utf8.MaxRune //U+10FFFF - maximum (and unallocated) code point 48 ) 49 50 // ChaincodeStub is an object passed to chaincode for shim side handling of 51 // APIs. 52 type ChaincodeStub struct { 53 TxID string 54 chaincodeEvent *pb.ChaincodeEvent 55 args [][]byte 56 handler *Handler 57 proposal *pb.Proposal 58 59 // Additional fields extracted from the proposal 60 creator []byte 61 transient map[string][]byte 62 binding []byte 63 } 64 65 // Peer address derived from command line or env var 66 var peerAddress string 67 68 // Start is the entry point for chaincodes bootstrap. It is not an API for 69 // chaincodes. 70 func Start(cc Chaincode) error { 71 // If Start() is called, we assume this is a standalone chaincode and set 72 // up formatted logging. 73 format := logging.MustStringFormatter("%{time:15:04:05.000} [%{module}] %{level:.4s} : %{message}") 74 backend := logging.NewLogBackend(os.Stderr, "", 0) 75 backendFormatter := logging.NewBackendFormatter(backend, format) 76 logging.SetBackend(backendFormatter).SetLevel(logging.Level(shimLoggingLevel), "shim") 77 78 SetChaincodeLoggingLevel() 79 80 err := factory.InitFactories(&factory.DefaultOpts) 81 if err != nil { 82 return fmt.Errorf("Internal error, BCCSP could not be initialized with default options: %s", err) 83 } 84 85 flag.StringVar(&peerAddress, "peer.address", "", "peer address") 86 87 flag.Parse() 88 89 chaincodeLogger.Debugf("Peer address: %s", getPeerAddress()) 90 91 // Establish connection with validating peer 92 clientConn, err := newPeerClientConnection() 93 if err != nil { 94 chaincodeLogger.Errorf("Error trying to connect to local peer: %s", err) 95 return fmt.Errorf("Error trying to connect to local peer: %s", err) 96 } 97 98 chaincodeLogger.Debugf("os.Args returns: %s", os.Args) 99 100 chaincodeSupportClient := pb.NewChaincodeSupportClient(clientConn) 101 102 // Establish stream with validating peer 103 stream, err := chaincodeSupportClient.Register(context.Background()) 104 if err != nil { 105 return fmt.Errorf("Error chatting with leader at address=%s: %s", getPeerAddress(), err) 106 } 107 108 chaincodename := viper.GetString("chaincode.id.name") 109 if chaincodename == "" { 110 return fmt.Errorf("Error chaincode id not provided") 111 } 112 err = chatWithPeer(chaincodename, stream, cc) 113 114 return err 115 } 116 117 // IsEnabledForLogLevel checks to see if the chaincodeLogger is enabled for a specific logging level 118 // used primarily for testing 119 func IsEnabledForLogLevel(logLevel string) bool { 120 lvl, _ := logging.LogLevel(logLevel) 121 return chaincodeLogger.IsEnabledFor(lvl) 122 } 123 124 // SetChaincodeLoggingLevel sets the chaincode logging level to the value 125 // of CORE_LOGGING_CHAINCODE set from core.yaml by chaincode_support.go 126 func SetChaincodeLoggingLevel() { 127 viper.SetEnvPrefix("CORE") 128 viper.AutomaticEnv() 129 replacer := strings.NewReplacer(".", "_") 130 viper.SetEnvKeyReplacer(replacer) 131 132 chaincodeLogLevelString := viper.GetString("logging.chaincode") 133 if chaincodeLogLevelString == "" { 134 shimLogLevelDefault := logging.Level(shimLoggingLevel) 135 chaincodeLogger.Infof("Chaincode log level not provided; defaulting to: %s", shimLogLevelDefault) 136 } else { 137 chaincodeLogLevel, err := LogLevel(chaincodeLogLevelString) 138 if err == nil { 139 SetLoggingLevel(chaincodeLogLevel) 140 } else { 141 chaincodeLogger.Warningf("Error: %s for chaincode log level: %s", err, chaincodeLogLevelString) 142 } 143 } 144 145 } 146 147 // StartInProc is an entry point for system chaincodes bootstrap. It is not an 148 // API for chaincodes. 149 func StartInProc(env []string, args []string, cc Chaincode, recv <-chan *pb.ChaincodeMessage, send chan<- *pb.ChaincodeMessage) error { 150 chaincodeLogger.Debugf("in proc %v", args) 151 152 var chaincodename string 153 for _, v := range env { 154 if strings.Index(v, "CORE_CHAINCODE_ID_NAME=") == 0 { 155 p := strings.SplitAfter(v, "CORE_CHAINCODE_ID_NAME=") 156 chaincodename = p[1] 157 break 158 } 159 } 160 if chaincodename == "" { 161 return fmt.Errorf("Error chaincode id not provided") 162 } 163 chaincodeLogger.Debugf("starting chat with peer using name=%s", chaincodename) 164 stream := newInProcStream(recv, send) 165 err := chatWithPeer(chaincodename, stream, cc) 166 return err 167 } 168 169 func getPeerAddress() string { 170 if peerAddress != "" { 171 return peerAddress 172 } 173 174 if peerAddress = viper.GetString("peer.address"); peerAddress == "" { 175 chaincodeLogger.Fatalf("peer.address not configured, can't connect to peer") 176 } 177 178 return peerAddress 179 } 180 181 func newPeerClientConnection() (*grpc.ClientConn, error) { 182 var peerAddress = getPeerAddress() 183 if comm.TLSEnabled() { 184 return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer()) 185 } 186 return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil) 187 } 188 189 func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode) error { 190 191 // Create the shim handler responsible for all control logic 192 handler := newChaincodeHandler(stream, cc) 193 194 defer stream.CloseSend() 195 // Send the ChaincodeID during register. 196 chaincodeID := &pb.ChaincodeID{Name: chaincodename} 197 payload, err := proto.Marshal(chaincodeID) 198 if err != nil { 199 return fmt.Errorf("Error marshalling chaincodeID during chaincode registration: %s", err) 200 } 201 // Register on the stream 202 chaincodeLogger.Debugf("Registering.. sending %s", pb.ChaincodeMessage_REGISTER) 203 if err = handler.serialSend(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload}); err != nil { 204 return fmt.Errorf("Error sending chaincode REGISTER: %s", err) 205 } 206 waitc := make(chan struct{}) 207 errc := make(chan error) 208 go func() { 209 defer close(waitc) 210 msgAvail := make(chan *pb.ChaincodeMessage) 211 var nsInfo *nextStateInfo 212 var in *pb.ChaincodeMessage 213 recv := true 214 for { 215 in = nil 216 err = nil 217 nsInfo = nil 218 if recv { 219 recv = false 220 go func() { 221 var in2 *pb.ChaincodeMessage 222 in2, err = stream.Recv() 223 msgAvail <- in2 224 }() 225 } 226 select { 227 case sendErr := <-errc: 228 //serialSendAsync successful? 229 if sendErr == nil { 230 continue 231 } 232 //no, bail 233 err = fmt.Errorf("Error sending %s: %s", in.Type.String(), sendErr) 234 return 235 case in = <-msgAvail: 236 if err == io.EOF { 237 chaincodeLogger.Debugf("Received EOF, ending chaincode stream, %s", err) 238 return 239 } else if err != nil { 240 chaincodeLogger.Errorf("Received error from server: %s, ending chaincode stream", err) 241 return 242 } else if in == nil { 243 err = fmt.Errorf("Received nil message, ending chaincode stream") 244 chaincodeLogger.Debug("Received nil message, ending chaincode stream") 245 return 246 } 247 chaincodeLogger.Debugf("[%s]Received message %s from shim", shorttxid(in.Txid), in.Type.String()) 248 recv = true 249 case nsInfo = <-handler.nextState: 250 in = nsInfo.msg 251 if in == nil { 252 panic("nil msg") 253 } 254 chaincodeLogger.Debugf("[%s]Move state message %s", shorttxid(in.Txid), in.Type.String()) 255 } 256 257 // Call FSM.handleMessage() 258 err = handler.handleMessage(in) 259 if err != nil { 260 err = fmt.Errorf("Error handling message: %s", err) 261 return 262 } 263 264 //keepalive messages are PONGs to the fabric's PINGs 265 if (nsInfo != nil && nsInfo.sendToCC) || (in.Type == pb.ChaincodeMessage_KEEPALIVE) { 266 if in.Type == pb.ChaincodeMessage_KEEPALIVE { 267 chaincodeLogger.Debug("Sending KEEPALIVE response") 268 //ignore any errors, maybe next KEEPALIVE will work 269 handler.serialSendAsync(in, nil) 270 } else { 271 chaincodeLogger.Debugf("[%s]send state message %s", shorttxid(in.Txid), in.Type.String()) 272 handler.serialSendAsync(in, errc) 273 } 274 } 275 } 276 }() 277 <-waitc 278 return err 279 } 280 281 // -- init stub --- 282 // ChaincodeInvocation functionality 283 284 func (stub *ChaincodeStub) init(handler *Handler, txid string, input *pb.ChaincodeInput, proposal *pb.Proposal) error { 285 stub.TxID = txid 286 stub.args = input.Args 287 stub.handler = handler 288 stub.proposal = proposal 289 290 // TODO: sanity check: verify that every call to init with a nil 291 // proposal is a legitimate one, meaning it is an internal call 292 // to system chaincodes. 293 if proposal != nil { 294 // Extract creator, transient, binding... 295 var err error 296 stub.creator, stub.transient, err = utils.GetChaincodeProposalContext(proposal) 297 if err != nil { 298 return fmt.Errorf("Failed extracting proposal fields. [%s]", err) 299 } 300 301 // TODO: txid must uniquely identity the transaction. 302 // Remove this comment once replay attack protection will be in place 303 stub.binding, err = utils.ComputeProposalBinding(proposal) 304 if err != nil { 305 return fmt.Errorf("Failed computing binding from proposal. [%s]", err) 306 } 307 } 308 309 return nil 310 } 311 312 // GetTxID returns the transaction ID 313 func (stub *ChaincodeStub) GetTxID() string { 314 return stub.TxID 315 } 316 317 // --------- Security functions ---------- 318 //CHAINCODE SEC INTERFACE FUNCS TOBE IMPLEMENTED BY ANGELO 319 320 // ------------- Call Chaincode functions --------------- 321 322 // InvokeChaincode locally calls the specified chaincode `Invoke` using the 323 // same transaction context; that is, chaincode calling chaincode doesn't 324 // create a new transaction message. 325 func (stub *ChaincodeStub) InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response { 326 // Internally we handle chaincode name as a composite name 327 if channel != "" { 328 chaincodeName = chaincodeName + "/" + channel 329 } 330 return stub.handler.handleInvokeChaincode(chaincodeName, args, stub.TxID) 331 } 332 333 // --------- State functions ---------- 334 335 // GetState returns the byte array value specified by the `key`. 336 func (stub *ChaincodeStub) GetState(key string) ([]byte, error) { 337 return stub.handler.handleGetState(key, stub.TxID) 338 } 339 340 // PutState writes the specified `value` and `key` into the ledger. 341 func (stub *ChaincodeStub) PutState(key string, value []byte) error { 342 return stub.handler.handlePutState(key, value, stub.TxID) 343 } 344 345 // DelState removes the specified `key` and its value from the ledger. 346 func (stub *ChaincodeStub) DelState(key string) error { 347 return stub.handler.handleDelState(key, stub.TxID) 348 } 349 350 // StateQueryIterator allows a chaincode to iterate over a set of 351 // key/value pairs in the state. 352 type StateQueryIterator struct { 353 handler *Handler 354 uuid string 355 response *pb.QueryStateResponse 356 currentLoc int 357 } 358 359 // GetStateByRange function can be invoked by a chaincode to query of a range 360 // of keys in the state. Assuming the startKey and endKey are in lexical order, 361 // an iterator will be returned that can be used to iterate over all keys 362 // between the startKey and endKey, inclusive. The order in which keys are 363 // returned by the iterator is random. 364 func (stub *ChaincodeStub) GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) { 365 response, err := stub.handler.handleGetStateByRange(startKey, endKey, stub.TxID) 366 if err != nil { 367 return nil, err 368 } 369 return &StateQueryIterator{stub.handler, stub.TxID, response, 0}, nil 370 } 371 372 // GetQueryResult function can be invoked by a chaincode to perform a 373 // rich query against state database. Only supported by state database implementations 374 // that support rich query. The query string is in the syntax of the underlying 375 // state database. An iterator is returned which can be used to iterate (next) over 376 // the query result set 377 func (stub *ChaincodeStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) { 378 response, err := stub.handler.handleGetQueryResult(query, stub.TxID) 379 if err != nil { 380 return nil, err 381 } 382 return &StateQueryIterator{stub.handler, stub.TxID, response, 0}, nil 383 } 384 385 // GetHistoryForKey function can be invoked by a chaincode to return a history of 386 // key values across time. GetHistoryForKey is intended to be used for read-only queries. 387 func (stub *ChaincodeStub) GetHistoryForKey(key string) (StateQueryIteratorInterface, error) { 388 response, err := stub.handler.handleGetHistoryForKey(key, stub.TxID) 389 if err != nil { 390 return nil, err 391 } 392 return &StateQueryIterator{stub.handler, stub.TxID, response, 0}, nil 393 } 394 395 //CreateCompositeKey combines the given attributes to form a composite key. 396 func (stub *ChaincodeStub) CreateCompositeKey(objectType string, attributes []string) (string, error) { 397 return createCompositeKey(objectType, attributes) 398 } 399 400 //SplitCompositeKey splits the key into attributes on which the composite key was formed. 401 func (stub *ChaincodeStub) SplitCompositeKey(compositeKey string) (string, []string, error) { 402 return splitCompositeKey(compositeKey) 403 } 404 405 func createCompositeKey(objectType string, attributes []string) (string, error) { 406 if err := validateCompositeKeyAttribute(objectType); err != nil { 407 return "", err 408 } 409 ck := objectType + string(minUnicodeRuneValue) 410 for _, att := range attributes { 411 if err := validateCompositeKeyAttribute(att); err != nil { 412 return "", err 413 } 414 ck += att + string(minUnicodeRuneValue) 415 } 416 return ck, nil 417 } 418 419 func splitCompositeKey(compositeKey string) (string, []string, error) { 420 componentIndex := 0 421 components := []string{} 422 for i := 0; i < len(compositeKey); i++ { 423 if compositeKey[i] == minUnicodeRuneValue { 424 components = append(components, compositeKey[componentIndex:i]) 425 componentIndex = i + 1 426 } 427 } 428 return components[0], components[1:], nil 429 } 430 431 func validateCompositeKeyAttribute(str string) error { 432 if !utf8.ValidString(str) { 433 return fmt.Errorf("Not a valid utf8 string: [%x]", str) 434 } 435 for index, runeValue := range str { 436 if runeValue == minUnicodeRuneValue || runeValue == maxUnicodeRuneValue { 437 return fmt.Errorf(`Input contain unicode %#U starting at position [%d]. %#U and %#U are not allowed in the input attribute of a composite key`, 438 runeValue, index, minUnicodeRuneValue, maxUnicodeRuneValue) 439 } 440 } 441 return nil 442 } 443 444 //GetStateByPartialCompositeKey function can be invoked by a chaincode to query the 445 //state based on a given partial composite key. This function returns an 446 //iterator which can be used to iterate over all composite keys whose prefix 447 //matches the given partial composite key. This function should be used only for 448 //a partial composite key. For a full composite key, an iter with empty response 449 //would be returned. 450 func (stub *ChaincodeStub) GetStateByPartialCompositeKey(objectType string, attributes []string) (StateQueryIteratorInterface, error) { 451 return getStateByPartialCompositeKey(stub, objectType, attributes) 452 } 453 454 func getStateByPartialCompositeKey(stub ChaincodeStubInterface, objectType string, attributes []string) (StateQueryIteratorInterface, error) { 455 partialCompositeKey, _ := stub.CreateCompositeKey(objectType, attributes) 456 keysIter, err := stub.GetStateByRange(partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue)) 457 if err != nil { 458 return nil, fmt.Errorf("Error fetching rows: %s", err) 459 } 460 return keysIter, nil 461 } 462 463 // HasNext returns true if the range query iterator contains additional keys 464 // and values. 465 func (iter *StateQueryIterator) HasNext() bool { 466 if iter.currentLoc < len(iter.response.KeysAndValues) || iter.response.HasMore { 467 return true 468 } 469 return false 470 } 471 472 // Next returns the next key and value in the range query iterator. 473 func (iter *StateQueryIterator) Next() (string, []byte, error) { 474 if iter.currentLoc < len(iter.response.KeysAndValues) { 475 keyValue := iter.response.KeysAndValues[iter.currentLoc] 476 iter.currentLoc++ 477 return keyValue.Key, keyValue.Value, nil 478 } else if !iter.response.HasMore { 479 return "", nil, errors.New("No such key") 480 } else { 481 response, err := iter.handler.handleQueryStateNext(iter.response.Id, iter.uuid) 482 483 if err != nil { 484 return "", nil, err 485 } 486 487 iter.currentLoc = 0 488 iter.response = response 489 keyValue := iter.response.KeysAndValues[iter.currentLoc] 490 iter.currentLoc++ 491 return keyValue.Key, keyValue.Value, nil 492 493 } 494 } 495 496 // Close closes the range query iterator. This should be called when done 497 // reading from the iterator to free up resources. 498 func (iter *StateQueryIterator) Close() error { 499 _, err := iter.handler.handleQueryStateClose(iter.response.Id, iter.uuid) 500 return err 501 } 502 503 // GetArgs returns the argument list 504 func (stub *ChaincodeStub) GetArgs() [][]byte { 505 return stub.args 506 } 507 508 // GetStringArgs returns the arguments as array of strings 509 func (stub *ChaincodeStub) GetStringArgs() []string { 510 args := stub.GetArgs() 511 strargs := make([]string, 0, len(args)) 512 for _, barg := range args { 513 strargs = append(strargs, string(barg)) 514 } 515 return strargs 516 } 517 518 // GetFunctionAndParameters returns the first arg as the function and the rest 519 // as argument string array 520 func (stub *ChaincodeStub) GetFunctionAndParameters() (function string, params []string) { 521 allargs := stub.GetStringArgs() 522 function = "" 523 params = []string{} 524 if len(allargs) >= 1 { 525 function = allargs[0] 526 params = allargs[1:] 527 } 528 return 529 } 530 531 // GetCreator returns SignatureHeader.Creator of the proposal 532 // this Stub refers to. 533 func (stub *ChaincodeStub) GetCreator() ([]byte, error) { 534 return stub.creator, nil 535 } 536 537 // GetTransient returns the ChaincodeProposalPayload.transient field. 538 // It is a map that contains data (e.g. cryptographic material) 539 // that might be used to implement some form of application-level confidentiality. The contents 540 // of this field, as prescribed by ChaincodeProposalPayload, are supposed to always 541 // be omitted from the transaction and excluded from the ledger. 542 func (stub *ChaincodeStub) GetTransient() (map[string][]byte, error) { 543 return stub.transient, nil 544 } 545 546 // GetBinding returns the transaction binding 547 func (stub *ChaincodeStub) GetBinding() ([]byte, error) { 548 return stub.binding, nil 549 } 550 551 // GetArgsSlice returns the arguments to the stub call as a byte array 552 func (stub *ChaincodeStub) GetArgsSlice() ([]byte, error) { 553 args := stub.GetArgs() 554 res := []byte{} 555 for _, barg := range args { 556 res = append(res, barg...) 557 } 558 return res, nil 559 } 560 561 // GetTxTimestamp returns transaction created timestamp, which is currently 562 // taken from the peer receiving the transaction. Note that this timestamp 563 // may not be the same with the other peers' time. 564 func (stub *ChaincodeStub) GetTxTimestamp() (*timestamp.Timestamp, error) { 565 return nil, nil 566 } 567 568 // ------------- ChaincodeEvent API ---------------------- 569 570 // SetEvent saves the event to be sent when a transaction is made part of a block 571 func (stub *ChaincodeStub) SetEvent(name string, payload []byte) error { 572 if name == "" { 573 return errors.New("Event name can not be nil string.") 574 } 575 stub.chaincodeEvent = &pb.ChaincodeEvent{EventName: name, Payload: payload} 576 return nil 577 } 578 579 // ------------- Logging Control and Chaincode Loggers --------------- 580 581 // As independent programs, Go language chaincodes can use any logging 582 // methodology they choose, from simple fmt.Printf() to os.Stdout, to 583 // decorated logs created by the author's favorite logging package. The 584 // chaincode "shim" interface, however, is defined by the Hyperledger fabric 585 // and implements its own logging methodology. This methodology currently 586 // includes severity-based logging control and a standard way of decorating 587 // the logs. 588 // 589 // The facilities defined here allow a Go language chaincode to control the 590 // logging level of its shim, and to create its own logs formatted 591 // consistently with, and temporally interleaved with the shim logs without 592 // any knowledge of the underlying implementation of the shim, and without any 593 // other package requirements. The lack of package requirements is especially 594 // important because even if the chaincode happened to explicitly use the same 595 // logging package as the shim, unless the chaincode is physically included as 596 // part of the hyperledger fabric source code tree it could actually end up 597 // using a distinct binary instance of the logging package, with different 598 // formats and severity levels than the binary package used by the shim. 599 // 600 // Another approach that might have been taken, and could potentially be taken 601 // in the future, would be for the chaincode to supply a logging object for 602 // the shim to use, rather than the other way around as implemented 603 // here. There would be some complexities associated with that approach, so 604 // for the moment we have chosen the simpler implementation below. The shim 605 // provides one or more abstract logging objects for the chaincode to use via 606 // the NewLogger() API, and allows the chaincode to control the severity level 607 // of shim logs using the SetLoggingLevel() API. 608 609 // LoggingLevel is an enumerated type of severity levels that control 610 // chaincode logging. 611 type LoggingLevel logging.Level 612 613 // These constants comprise the LoggingLevel enumeration 614 const ( 615 LogDebug = LoggingLevel(logging.DEBUG) 616 LogInfo = LoggingLevel(logging.INFO) 617 LogNotice = LoggingLevel(logging.NOTICE) 618 LogWarning = LoggingLevel(logging.WARNING) 619 LogError = LoggingLevel(logging.ERROR) 620 LogCritical = LoggingLevel(logging.CRITICAL) 621 ) 622 623 var shimLoggingLevel = LogDebug // Necessary for correct initialization; See Start() 624 625 // SetLoggingLevel allows a Go language chaincode to set the logging level of 626 // its shim. 627 func SetLoggingLevel(level LoggingLevel) { 628 shimLoggingLevel = level 629 logging.SetLevel(logging.Level(level), "shim") 630 } 631 632 // LogLevel converts a case-insensitive string chosen from CRITICAL, ERROR, 633 // WARNING, NOTICE, INFO or DEBUG into an element of the LoggingLevel 634 // type. In the event of errors the level returned is LogError. 635 func LogLevel(levelString string) (LoggingLevel, error) { 636 l, err := logging.LogLevel(levelString) 637 level := LoggingLevel(l) 638 if err != nil { 639 level = LogError 640 } 641 return level, err 642 } 643 644 // ------------- Chaincode Loggers --------------- 645 646 // ChaincodeLogger is an abstraction of a logging object for use by 647 // chaincodes. These objects are created by the NewLogger API. 648 type ChaincodeLogger struct { 649 logger *logging.Logger 650 } 651 652 // NewLogger allows a Go language chaincode to create one or more logging 653 // objects whose logs will be formatted consistently with, and temporally 654 // interleaved with the logs created by the shim interface. The logs created 655 // by this object can be distinguished from shim logs by the name provided, 656 // which will appear in the logs. 657 func NewLogger(name string) *ChaincodeLogger { 658 return &ChaincodeLogger{logging.MustGetLogger(name)} 659 } 660 661 // SetLevel sets the logging level for a chaincode logger. Note that currently 662 // the levels are actually controlled by the name given when the logger is 663 // created, so loggers should be given unique names other than "shim". 664 func (c *ChaincodeLogger) SetLevel(level LoggingLevel) { 665 logging.SetLevel(logging.Level(level), c.logger.Module) 666 } 667 668 // IsEnabledFor returns true if the logger is enabled to creates logs at the 669 // given logging level. 670 func (c *ChaincodeLogger) IsEnabledFor(level LoggingLevel) bool { 671 return c.logger.IsEnabledFor(logging.Level(level)) 672 } 673 674 // Debug logs will only appear if the ChaincodeLogger LoggingLevel is set to 675 // LogDebug. 676 func (c *ChaincodeLogger) Debug(args ...interface{}) { 677 c.logger.Debug(args...) 678 } 679 680 // Info logs will appear if the ChaincodeLogger LoggingLevel is set to 681 // LogInfo or LogDebug. 682 func (c *ChaincodeLogger) Info(args ...interface{}) { 683 c.logger.Info(args...) 684 } 685 686 // Notice logs will appear if the ChaincodeLogger LoggingLevel is set to 687 // LogNotice, LogInfo or LogDebug. 688 func (c *ChaincodeLogger) Notice(args ...interface{}) { 689 c.logger.Notice(args...) 690 } 691 692 // Warning logs will appear if the ChaincodeLogger LoggingLevel is set to 693 // LogWarning, LogNotice, LogInfo or LogDebug. 694 func (c *ChaincodeLogger) Warning(args ...interface{}) { 695 c.logger.Warning(args...) 696 } 697 698 // Error logs will appear if the ChaincodeLogger LoggingLevel is set to 699 // LogError, LogWarning, LogNotice, LogInfo or LogDebug. 700 func (c *ChaincodeLogger) Error(args ...interface{}) { 701 c.logger.Error(args...) 702 } 703 704 // Critical logs always appear; They can not be disabled. 705 func (c *ChaincodeLogger) Critical(args ...interface{}) { 706 c.logger.Critical(args...) 707 } 708 709 // Debugf logs will only appear if the ChaincodeLogger LoggingLevel is set to 710 // LogDebug. 711 func (c *ChaincodeLogger) Debugf(format string, args ...interface{}) { 712 c.logger.Debugf(format, args...) 713 } 714 715 // Infof logs will appear if the ChaincodeLogger LoggingLevel is set to 716 // LogInfo or LogDebug. 717 func (c *ChaincodeLogger) Infof(format string, args ...interface{}) { 718 c.logger.Infof(format, args...) 719 } 720 721 // Noticef logs will appear if the ChaincodeLogger LoggingLevel is set to 722 // LogNotice, LogInfo or LogDebug. 723 func (c *ChaincodeLogger) Noticef(format string, args ...interface{}) { 724 c.logger.Noticef(format, args...) 725 } 726 727 // Warningf logs will appear if the ChaincodeLogger LoggingLevel is set to 728 // LogWarning, LogNotice, LogInfo or LogDebug. 729 func (c *ChaincodeLogger) Warningf(format string, args ...interface{}) { 730 c.logger.Warningf(format, args...) 731 } 732 733 // Errorf logs will appear if the ChaincodeLogger LoggingLevel is set to 734 // LogError, LogWarning, LogNotice, LogInfo or LogDebug. 735 func (c *ChaincodeLogger) Errorf(format string, args ...interface{}) { 736 c.logger.Errorf(format, args...) 737 } 738 739 // Criticalf logs always appear; They can not be disabled. 740 func (c *ChaincodeLogger) Criticalf(format string, args ...interface{}) { 741 c.logger.Criticalf(format, args...) 742 }