Add LogConfig for Producer/PushConsumer
diff --git a/core/api.go b/core/api.go
index 69f3567..a159c87 100644
--- a/core/api.go
+++ b/core/api.go
@@ -36,7 +36,7 @@
 	InstanceName     string
 	Credentials      *SessionCredentials
 
-	// TODO log config
+	logC *LogConfig
 	SendMsgTimeout int
 	CompressLevel  int
 	MaxMessageSize int
@@ -75,7 +75,7 @@
 	InstanceName     string
 	Credentials      *SessionCredentials
 
-	// TODO log config
+	logC *LogConfig
 	ThreadCount         int
 	MessageBatchMaxSize int
 	Model               MessageModel
@@ -89,6 +89,7 @@
 
 type PushConsumer interface {
 	baseAPI
+
 	// Subscribe a new topic with specify filter expression and consume function.
 	Subscribe(topic, expression string, consumeFunc func(msg *MessageExt) ConsumeStatus) error
 }
@@ -98,6 +99,7 @@
 	baseAPI
 	// Pull returns the messages from the consume queue by specify the offset and the max number
 	Pull(mq MessageQueue, subExpression string, offset int64, maxNums int) PullResult
+
 	// FetchSubscriptionMessageQueues returns the consume queue of the topic
 	FetchSubscriptionMessageQueues(topic string) []MessageQueue
 }
diff --git a/core/cfuns.go b/core/cfuns.go
index 7fe4ffe..5b4cba9 100644
--- a/core/cfuns.go
+++ b/core/cfuns.go
@@ -36,6 +36,7 @@
 	}
 
 	msgExt := cmsgExtToGo(msg)
+	//C.DestroyMessageExt(msg)
 	cfunc, exist := consumer.(*defaultPushConsumer).funcsMap.Load(msgExt.Topic)
 	if !exist {
 		return C.int(ReConsumeLater)
diff --git a/core/log.go b/core/log.go
index e081e4c..5ff244e 100644
--- a/core/log.go
+++ b/core/log.go
@@ -37,6 +37,27 @@
 	LogLevelNum   = LogLevel(C.E_LOG_LEVEL_LEVEL_NUM)
 )
 
+func (l LogLevel) String() string {
+	switch l {
+	case LogLevelFatal:
+		return "Fatal"
+	case LogLevelError:
+		return "Error"
+	case LogLevelWarn:
+		return "Warn"
+	case LogLevelInfo:
+		return "Info"
+	case LogLevelDebug:
+		return "Debug"
+	case LogLevelTrace:
+		return "Trace"
+	case LogLevelNum:
+		return "Num"
+	default:
+		return "Unkonw"
+	}
+}
+
 // LogConfig the log configuration for the pull consumer
 type LogConfig struct {
 	Path     string
diff --git a/core/log_test.go b/core/log_test.go
new file mode 100644
index 0000000..f06d1c7
--- /dev/null
+++ b/core/log_test.go
@@ -0,0 +1,22 @@
+package rocketmq
+
+import (
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestLogConfig_String(t *testing.T) {
+	logc := LogConfig{Path: "/log/path1", FileNum: 3, FileSize: 1 << 20, Level:LogLevelDebug}
+	assert.Equal(t, "{Path:/log/path1 FileNum:3 FileSize:1048576 Level:Debug}", logc.String())
+	logc.Level = LogLevelFatal
+	assert.Equal(t, "{Path:/log/path1 FileNum:3 FileSize:1048576 Level:Fatal}", logc.String())
+	logc.Level = LogLevelError
+	assert.Equal(t, "{Path:/log/path1 FileNum:3 FileSize:1048576 Level:Error}", logc.String())
+	logc.Level = LogLevelWarn
+	assert.Equal(t, "{Path:/log/path1 FileNum:3 FileSize:1048576 Level:Warn}", logc.String())
+	logc.Level = LogLevelInfo
+	assert.Equal(t, "{Path:/log/path1 FileNum:3 FileSize:1048576 Level:Info}", logc.String())
+	logc.Level = LogLevelTrace
+	assert.Equal(t, "{Path:/log/path1 FileNum:3 FileSize:1048576 Level:Trace}", logc.String())
+	logc.Level = LogLevelError
+}
diff --git a/core/message.go b/core/message.go
index 98dc6cb..76ec80c 100644
--- a/core/message.go
+++ b/core/message.go
@@ -16,80 +16,105 @@
  */
 package rocketmq
 
-//#cgo LDFLAGS: -L/usr/local/lib/ -lrocketmq
-//#include "rocketmq/CMessage.h"
-//#include "rocketmq/CMessageExt.h"
+/*
+#cgo LDFLAGS: -L/usr/local/lib/ -lrocketmq
+#include "rocketmq/CMessage.h"
+#include "rocketmq/CMessageExt.h"
+#include <stdlib.h>
+*/
 import "C"
-import "fmt"
+import (
+	"fmt"
+	"unsafe"
+)
 
 type Message struct {
-	Topic string
-	Keys  string
-	// improve: maybe []byte is better.
-	Body string
+	Topic          string
+	Tags           string
+	Keys           string
+	Body           string
+	DelayTimeLevel int
+	Property       map[string]string
 }
 
 func (msg *Message) String() string {
-	return fmt.Sprintf("[topic: %s, keys: %s, body: %s]", msg.Topic, msg.Keys, msg.Body)
+	return fmt.Sprintf("[Topic: %s, Tags: %s, Keys: %s, Body: %s, DelayTimeLevel: %d, Property: %v]",
+		msg.Topic, msg.Tags, msg.Keys, msg.Body, msg.DelayTimeLevel, msg.Property)
+}
+
+func goMsgToC(gomsg *Message) *C.struct_CMessage {
+	cs := C.CString(gomsg.Topic)
+	var cmsg = C.CreateMessage(cs)
+	C.free(unsafe.Pointer(cs))
+
+	cs =C.CString(gomsg.Tags)
+	C.SetMessageTags(cmsg, cs)
+	C.free(unsafe.Pointer(cs))
+
+	cs = C.CString(gomsg.Keys)
+	C.SetMessageKeys(cmsg, cs)
+	C.free(unsafe.Pointer(cs))
+
+	cs = C.CString(gomsg.Body)
+	C.SetMessageBody(cmsg, cs)
+	C.free(unsafe.Pointer(cs))
+
+	C.SetDelayTimeLevel(cmsg, C.int(gomsg.DelayTimeLevel))
+
+	for k, v := range gomsg.Property {
+		key := C.CString(k)
+		value := C.CString(v)
+		C.SetMessageProperty(cmsg, key, value)
+		C.free(unsafe.Pointer(key))
+		C.free(unsafe.Pointer(value))
+	}
+	return cmsg
 }
 
 type MessageExt struct {
 	Message
-	MessageID string
-	Tags      string
+	MessageID                 string
+	QueueId                   int
+	ReconsumeTimes            int
+	StoreSize                 int
+	BornTimestamp             int64
+	StoreTimestamp            int64
+	QueueOffset               int64
+	CommitLogOffset           int64
+	PreparedTransactionOffset int64
+
 	// improve: is there is a method convert c++ map to go variable?
 	cmsgExt *C.struct_CMessageExt
-	//Properties  string
 }
 
 func (msgExt *MessageExt) String() string {
-	return fmt.Sprintf("[messageId: %s, %s, Tags: %s]", msgExt.MessageID, msgExt.Message, msgExt.Tags)
+	return fmt.Sprintf("[MessageId: %s, %s, QueueId: %d, ReconsumeTimes: %d, StoreSize: %d, BornTimestamp: %d, " +
+		"StoreTimestamp: %d, QueueOffset: %d, CommitLogOffset: %d, PreparedTransactionOffset: %d]", msgExt.MessageID,
+		msgExt.Message.String(), msgExt.QueueId, msgExt.ReconsumeTimes, msgExt.StoreSize, msgExt.BornTimestamp,
+		msgExt.StoreTimestamp, msgExt.QueueOffset, msgExt.CommitLogOffset, msgExt.PreparedTransactionOffset)
 }
 
 func (msgExt *MessageExt) GetProperty(key string) string {
 	return C.GoString(C.GetMessageProperty(msgExt.cmsgExt, C.CString(key)))
 }
 
-func cmsgToGo(cmsg *C.struct_CMessage) *Message {
-	defer C.DestroyMessage(cmsg)
-	gomsg := &Message{}
-
-	return gomsg
-}
-
-func goMsgToC(gomsg *Message) *C.struct_CMessage {
-	var cmsg = C.CreateMessage(C.CString(gomsg.Topic))
-
-	// int(C.SetMessageKeys(msg.(*C.struct_CMessage),C.CString(keys)))
-	C.SetMessageKeys(cmsg, C.CString(gomsg.Keys))
-
-	// int(C.SetMessageBody(msg.(*C.struct_CMessage),C.CString(body)))
-	C.SetMessageBody(cmsg, C.CString(gomsg.Body))
-	return cmsg
-}
-
-//
 func cmsgExtToGo(cmsg *C.struct_CMessageExt) *MessageExt {
-	//defer C.DestroyMessageExt(cmsg)
-	gomsg := &MessageExt{}
+	gomsg := &MessageExt{cmsgExt: cmsg}
 
 	gomsg.Topic = C.GoString(C.GetMessageTopic(cmsg))
-	gomsg.Body = C.GoString(C.GetMessageBody(cmsg))
-	gomsg.Keys = C.GoString(C.GetMessageKeys(cmsg))
 	gomsg.Tags = C.GoString(C.GetMessageTags(cmsg))
+	gomsg.Keys = C.GoString(C.GetMessageKeys(cmsg))
+	gomsg.Body = C.GoString(C.GetMessageBody(cmsg))
 	gomsg.MessageID = C.GoString(C.GetMessageId(cmsg))
+	gomsg.DelayTimeLevel = int(C.GetMessageDelayTimeLevel(cmsg))
+	gomsg.QueueId = int(C.GetMessageQueueId(cmsg))
+	gomsg.ReconsumeTimes = int(C.GetMessageReconsumeTimes(cmsg))
+	gomsg.StoreSize = int(C.GetMessageStoreSize(cmsg))
+	gomsg.BornTimestamp = int64(C.GetMessageBornTimestamp(cmsg))
+	gomsg.StoreTimestamp = int64(C.GetMessageStoreTimestamp(cmsg))
+	gomsg.QueueOffset = int64(C.GetMessageQueueOffset(cmsg))
+	gomsg.CommitLogOffset = int64(C.GetMessageCommitLogOffset(cmsg))
+	gomsg.PreparedTransactionOffset = int64(C.GetMessagePreparedTransactionOffset(cmsg))
 
 	return gomsg
 }
-
-//
-//func goMsgExtToC(gomsg *MessageExt) *C.struct_CMessageExt {
-//	var cmsg = C.CreateMessage(C.CString(gomsg.Topic))
-//
-//	// int(C.SetMessageKeys(msg.(*C.struct_CMessage),C.CString(keys)))
-//	C.SetMessageKeys(cmsg, C.CString(gomsg.Keys))
-//
-//	// int(C.SetMessageBody(msg.(*C.struct_CMessage),C.CString(body)))
-//	C.SetMessageBody(cmsg, C.CString(gomsg.Body))
-//	return cmsg
-//}
diff --git a/core/message_test.go b/core/message_test.go
index 1d1f2a8..a86b81b 100644
--- a/core/message_test.go
+++ b/core/message_test.go
@@ -17,12 +17,44 @@
 package rocketmq
 
 import (
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 
-func TestGetMessageTopic(test *testing.T) {
-	//fmt.Println("-----TestGetMessageTopic Start----")
-	//msg := rocketmq.CreateMessage("testTopic")
-	//rocketmq.DestroyMessage(msg)
-	//fmt.Println("-----TestGetMessageTopic Finish----")
+func TestMessage_String(t *testing.T) {
+	msg := Message{
+		Topic: "testTopic",
+		Tags:"TagA, TagB",
+		Keys:"Key1, Key2",
+		Body:"Body1234567890",
+		DelayTimeLevel: 8,}
+	expect := "[Topic: testTopic, Tags: TagA, TagB, Keys: Key1, Key2, Body: Body1234567890, DelayTimeLevel: 8," +
+		" Property: map[]]"
+	assert.Equal(t, expect, msg.String())
+}
+
+func TestMessageExt_String(t *testing.T) {
+	msg := Message{
+		Topic: "testTopic",
+		Tags:"TagA, TagB",
+		Keys:"Key1, Key2",
+		Body:"Body1234567890",
+		DelayTimeLevel: 8,}
+	msgExt := MessageExt{
+		Message: msg,
+		MessageID: "messageId",
+		QueueId: 2,
+		ReconsumeTimes: 13,
+		StoreSize: 1 << 10,
+		BornTimestamp: int64(1234567890897),
+		StoreTimestamp: int64(1234567890),
+		QueueOffset: int64(1234567890),
+		CommitLogOffset: int64(1234567890),
+		PreparedTransactionOffset: int64(1234567890),
+	}
+	expect := "[MessageId: messageId, [Topic: testTopic, Tags: TagA, TagB, Keys: Key1, Key2, " +
+		"Body: Body1234567890, DelayTimeLevel: 8, Property: map[]], QueueId: 2, ReconsumeTimes: " +
+		"13, StoreSize: 1024, BornTimestamp: 1234567890897, StoreTimestamp: 1234567890, QueueOffset: 1234567890," +
+		" CommitLogOffset: 1234567890, PreparedTransactionOffset: 1234567890]"
+	assert.Equal(t, expect, msgExt.String())
 }
diff --git a/core/producer.go b/core/producer.go
index bd9ed19..bd326a5 100644
--- a/core/producer.go
+++ b/core/producer.go
@@ -20,6 +20,7 @@
 #cgo LDFLAGS: -L/usr/local/lib/ -lrocketmq
 
 #include <stdio.h>
+#include <stdlib.h>
 #include "rocketmq/CMessage.h"
 #include "rocketmq/CProducer.h"
 #include "rocketmq/CSendResult.h"
@@ -32,6 +33,7 @@
 import "C"
 import (
 	"errors"
+	"fmt"
 	log "github.com/sirupsen/logrus"
 	"unsafe"
 )
@@ -62,78 +64,105 @@
 
 func newDefaultProducer(config *ProducerConfig) (*defaultProducer, error) {
 	if config.GroupID == "" {
-		return nil, errors.New("GroupId is empty.")
+		return nil, errors.New("GroupId is empty")
 	}
 
 	if config.NameServer == "" && config.NameServerDomain == "" {
-		return nil, errors.New("NameServer and NameServerDomain is empty.")
+		return nil, errors.New("NameServer and NameServerDomain is empty")
 	}
 
 
 	producer := &defaultProducer{config: config}
-	cproduer := C.CreateProducer(C.CString(config.GroupID))
+	cs := C.CString(config.GroupID)
+	cproduer := C.CreateProducer(cs)
+	C.free(unsafe.Pointer(cs))
 	
 	if cproduer == nil {
-		log.Fatal("Create Producer failed, please check cpp logs for details.")
+		return nil, errors.New("create Producer failed, please check cpp logs for details")
 	}
 
 	var code int
 	if config.NameServer != "" {
-		code = int(C.SetProducerNameServerAddress(cproduer, C.CString(config.NameServer)))
+		cs = C.CString(config.NameServer)
+		code = int(C.SetProducerNameServerAddress(cproduer, cs))
+		C.free(unsafe.Pointer(cs))
 		if code != 0 {
-			log.Fatalf("Producer Set NameServerAddress error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set NameServerAddress error, code is: %d" +
+				"please check cpp logs for details", code))
 		}
 	}
 
 	if config.NameServerDomain != "" {
-		code = int(C.SetProducerNameServerDomain(cproduer, C.CString(config.NameServerDomain)))
+		cs = C.CString(config.NameServerDomain)
+		code = int(C.SetProducerNameServerDomain(cproduer, cs))
+		C.free(unsafe.Pointer(cs))
 		if code != 0 {
-			log.Fatalf("Producer Set NameServerDomain error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set NameServerDomain error, code is: %d" +
+				"please check cpp logs for details", code))
 		}
 	}
 
 	if config.InstanceName != "" {
-		code = int(C.SetProducerInstanceName(cproduer, C.CString(config.InstanceName)))
+		cs = C.CString(config.InstanceName)
+		code = int(C.SetProducerInstanceName(cproduer, cs))
+		C.free(unsafe.Pointer(cs))
 		if code != 0 {
-			log.Fatalf("Producer Set InstanceName error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set InstanceName error, code is: %d" +
+				"please check cpp logs for details", code))
 		}
 	}
 
 	if config.Credentials != nil {
-		code = int(C.SetProducerSessionCredentials(cproduer,
-			C.CString(config.Credentials.AccessKey),
-			C.CString(config.Credentials.SecretKey),
-			C.CString(config.Credentials.Channel)))
+		ak := C.CString(config.Credentials.AccessKey)
+		sk := C.CString(config.Credentials.SecretKey)
+		ch := C.CString(config.Credentials.Channel)
+		code = int(C.SetProducerSessionCredentials(cproduer, ak, sk, ch))
+
+		C.free(unsafe.Pointer(ak))
+		C.free(unsafe.Pointer(sk))
+		C.free(unsafe.Pointer(ch))
 		if code != 0 {
-			log.Fatalf("Producer Set Credentials error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set Credentials error, code is: %d", code))
+		}
+	}
+
+	if config.logC != nil {
+		cs = C.CString(config.logC.Path)
+		code = int(C.SetProducerLogPath(cproduer, cs))
+		C.free(unsafe.Pointer(cs))
+		if code != 0 {
+			return nil, errors.New(fmt.Sprintf("Producer Set LogPath error, code is: %d", code))
+		}
+
+		code = int(C.SetProducerLogFileNumAndSize(cproduer, C.int(config.logC.FileNum), C.long(config.logC.FileSize)))
+		if code != 0 {
+			return nil, errors.New(fmt.Sprintf("Producer Set FileNumAndSize error, code is: %d", code))
+		}
+
+		code = int(C.SetProducerLogLevel(cproduer, C.CLogLevel(config.logC.Level)))
+		if code != 0 {
+			return nil, errors.New(fmt.Sprintf("Producer Set LogLevel error, code is: %d", code))
 		}
 	}
 
 	if config.SendMsgTimeout > 0 {
 		code = int(C.SetProducerSendMsgTimeout(cproduer, C.int(config.SendMsgTimeout)))
 		if code != 0 {
-			log.Fatalf("Producer Set SendMsgTimeout error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set SendMsgTimeout error, code is: %d", code))
 		}
 	}
 
 	if config.CompressLevel > 0 {
 		code = int(C.SetProducerCompressLevel(cproduer, C.int(config.CompressLevel)))
 		if code != 0 {
-			log.Fatalf("Producer Set CompressLevel error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set CompressLevel error, code is: %d", code))
 		}
 	}
 
 	if config.MaxMessageSize > 0 {
 		code = int(C.SetProducerMaxMessageSize(cproduer, C.int(config.MaxMessageSize)))
 		if code != 0 {
-			log.Fatalf("Producer Set MaxMessageSize error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("Producer Set MaxMessageSize error, code is: %d", code))
 		}
 	}
 
@@ -154,7 +183,7 @@
 func (p *defaultProducer) Start() error {
 	code := int(C.StartProducer(p.cproduer))
 	if code != 0 {
-		 log.Fatalf("start producer error, error code is: %d", code)
+		 return errors.New(fmt.Sprintf("start producer error, error code is: %d", code))
 	}
 	return nil
 }
diff --git a/core/pull_consumer.go b/core/pull_consumer.go
index 19a033c..5796dc0 100644
--- a/core/pull_consumer.go
+++ b/core/pull_consumer.go
@@ -131,21 +131,21 @@
 func (c *DefaultPullConsumer) Start() error {
 	r := C.StartPullConsumer(c.cconsumer)
 	if r != 0 {
-		return fmt.Errorf("start failed, code:%d", r)
+		return fmt.Errorf("start failed, code:%d", int(r))
 	}
 	return nil
 }
 
-// Shutdown shutdown the pulling conumser
+// Shutdown shutdown the pulling consumer
 func (c *DefaultPullConsumer) Shutdown() error {
 	r := C.ShutdownPullConsumer(c.cconsumer)
 	if r != 0 {
-		return fmt.Errorf("shutdown failed, code:%d", r)
+		return fmt.Errorf("shutdown failed, code:%d", int(r))
 	}
 
 	r = C.DestroyPullConsumer(c.cconsumer)
 	if r != 0 {
-		return fmt.Errorf("destory failed, code:%d", r)
+		return fmt.Errorf("destory failed, code:%d", int(r))
 	}
 	return nil
 }
diff --git a/core/push_consumer.go b/core/push_consumer.go
index a0236e7..f332e3f 100644
--- a/core/push_consumer.go
+++ b/core/push_consumer.go
@@ -18,9 +18,9 @@
 
 /*
 #cgo LDFLAGS: -L/usr/local/lib -lrocketmq
+#include <stdlib.h>
 #include "rocketmq/CMessageExt.h"
 #include "rocketmq/CPushConsumer.h"
-#include "stdio.h"
 
 extern int consumeMessageCallback(CPushConsumer *consumer, CMessageExt *msg);
 
@@ -82,81 +82,100 @@
 		return nil, errors.New("NameServer and NameServerDomain is empty.")
 	}
 
-	//if config.Model == nil {
-	//	return nil, errors.New("MessageModel is nil")
-	//}
-
 	consumer := &defaultPushConsumer{config: config}
-	cconsumer := C.CreatePushConsumer(C.CString(config.GroupID))
+	cs := C.CString(config.GroupID)
+	cconsumer := C.CreatePushConsumer(cs)
+	C.free(unsafe.Pointer(cs))
 
 	if cconsumer == nil {
-		log.Fatal("Create PushConsumer failed, please check cpp logs for details.")
+		return nil, errors.New("Create PushConsumer failed")
 	}
 
 	var code int
 	if config.NameServer != "" {
-		code = int(C.SetPushConsumerNameServerAddress(cconsumer, C.CString(config.NameServer)))
+		cs = C.CString(config.NameServer)
+		code = int(C.SetPushConsumerNameServerAddress(cconsumer, cs))
+		C.free(unsafe.Pointer(cs))
 		if code != 0 {
-			 log.Fatalf("PushConsumer Set NameServerAddress error, code is: %d, " +
-			 	"please check cpp logs for details", code)
+			 return nil, errors.New(fmt.Sprintf(fmt.Sprintf("PushConsumer Set NameServerAddress error, code is: %d", code)))
 		}
 	}
 
 	if config.NameServerDomain != "" {
-		code = int(C.SetPushConsumerNameServerDomain(cconsumer, C.CString(config.NameServerDomain)))
+		cs = C.CString(config.NameServerDomain)
+		code = int(C.SetPushConsumerNameServerDomain(cconsumer, cs))
+		C.free(unsafe.Pointer(cs))
 		if code != 0 {
-			log.Fatalf("PushConsumer Set NameServerDomain error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return  nil, errors.New(fmt.Sprintf("PushConsumer Set NameServerDomain error, code is: %d", code))
 		}
 	}
 
 	if config.InstanceName != "" {
-		code = int(C.SetPushConsumerInstanceName(cconsumer, C.CString(config.InstanceName)))
+		cs = C.CString(config.InstanceName)
+		code = int(C.SetPushConsumerInstanceName(cconsumer, cs))
+		C.free(unsafe.Pointer(cs))
 		if code != 0 {
-			log.Fatalf("PushConsumer Set InstanceName error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("PushConsumer Set InstanceName error, code is: %d, " +
+				"please check cpp logs for details", code))
 		}
 	}
 
 	if config.Credentials != nil {
-		code = int(C.SetPushConsumerSessionCredentials(cconsumer,
-			C.CString(config.Credentials.AccessKey),
-			C.CString(config.Credentials.SecretKey),
-			C.CString(config.Credentials.Channel)))
+		ak := C.CString(config.Credentials.AccessKey)
+		sk := C.CString(config.Credentials.SecretKey)
+		ch := C.CString(config.Credentials.Channel)
+		code = int(C.SetPushConsumerSessionCredentials(cconsumer, ak, sk, ch))
+		C.free(unsafe.Pointer(ak))
+		C.free(unsafe.Pointer(sk))
+		C.free(unsafe.Pointer(ch))
 		if code != 0 {
-			log.Fatalf("PushConsumer Set Credentials error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("PushConsumer Set Credentials error, code is: %d", int(code)))
+		}
+	}
+
+	if config.logC != nil {
+		cs = C.CString(config.logC.Path)
+		code = int(C.SetProducerLogPath(cconsumer, cs))
+		C.free(unsafe.Pointer(cs))
+		if code != 0 {
+			return nil, errors.New(fmt.Sprintf("Producer Set LogPath error, code is: %d", code))
+		}
+
+		code = int(C.SetProducerLogFileNumAndSize(cconsumer, C.int(config.logC.FileNum), C.long(config.logC.FileSize)))
+		if code != 0 {
+			return nil, errors.New(fmt.Sprintf("Producer Set FileNumAndSize error, code is: %d", code))
+		}
+
+		code = int(C.SetProducerLogLevel(cconsumer, C.CLogLevel(config.logC.Level)))
+		if code != 0 {
+			return nil, errors.New(fmt.Sprintf("Producer Set LogLevel error, code is: %d", code))
 		}
 	}
 
 	if config.ThreadCount > 0 {
 		code = int(C.SetPushConsumerThreadCount(cconsumer, C.int(config.ThreadCount)))
 		if code != 0 {
-			log.Fatalf("PushConsumer Set ThreadCount error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("PushConsumer Set ThreadCount error, code is: %d", int(code)))
 		}
 	}
 
 	if config.MessageBatchMaxSize > 0 {
 		code = int(C.SetPushConsumerMessageBatchMaxSize(cconsumer, C.int(config.MessageBatchMaxSize)))
 		if code != 0 {
-			log.Fatalf("PushConsumer Set MessageBatchMaxSize error, code is: %d, " +
-				"please check cpp logs for details", code)
+			return nil, errors.New(fmt.Sprintf("PushConsumer Set MessageBatchMaxSize error, code is: %d", int(code)))
 		}
 	}
 
 	code = int(C.SetPushConsumerMessageModel(cconsumer, (C.CMessageModel)(config.Model)))
 
 	if code != 0 {
-		log.Fatalf("PushConsumer Set ConsumerMessageModel error, code is: %d, " +
-			"please check cpp logs for details", code)
+		return nil, errors.New(fmt.Sprintf("PushConsumer Set ConsumerMessageModel error, code is: %d", int(code)))
 	}
 
 	code = int(C.RegisterMessageCallback(cconsumer, (C.MessageCallBack)(unsafe.Pointer(C.callback_cgo))))
 
 	if code != 0 {
-		log.Fatalf("PushConsumer RegisterMessageCallback error, code is: %d, " +
-			"please check cpp logs for details", code)
+		return nil, errors.New(fmt.Sprintf("PushConsumer RegisterMessageCallback error, code is: %d", int(code)))
 	}
 
 	consumer.cconsumer = cconsumer
@@ -167,7 +186,7 @@
 func (c *defaultPushConsumer) Start() error {
 	code := C.StartPushConsumer(c.cconsumer)
 	if code != 0{
-		log.Fatalf("start PushConsumer error, code is: %d, please check cpp logs for details", code)
+		return errors.New(fmt.Sprintf("start PushConsumer error, code is: %d", int(code)))
 	}
 	return nil
 }
diff --git a/core/version.go b/core/version.go
index 5700714..4ac86d5 100644
--- a/core/version.go
+++ b/core/version.go
@@ -16,8 +16,8 @@
  */
 package rocketmq
 
-const GO_CLIENT_VERSION = "Go Client V1.0.0, BuildTime:2018.10.30"
+const GoClientVersion = "Go Client V1.0.0, BuildTime:2018.10.30"
 
 func GetVersion() (version string) {
-	return GO_CLIENT_VERSION
+	return GoClientVersion
 }