From 3da1c54848f46d5f74fb8d84d809e8cd53fdf564 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Mon, 4 Mar 2019 16:33:48 +0200 Subject: [PATCH] Add a method to mobile bindings that allows to dump content of the logs files (#1402) --- exportlogs/logs.go | 34 ++++++++++++++++++++++++++++++++++ exportlogs/logs_test.go | 30 ++++++++++++++++++++++++++++++ lib/library.go | 20 ++++++++++++++++++++ mobile/status.go | 20 ++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 exportlogs/logs.go create mode 100644 exportlogs/logs_test.go diff --git a/exportlogs/logs.go b/exportlogs/logs.go new file mode 100644 index 000000000..54854aa1d --- /dev/null +++ b/exportlogs/logs.go @@ -0,0 +1,34 @@ +package exportlogs + +import ( + "fmt" + "io/ioutil" + + "github.com/status-im/go-ethereum/common/hexutil" +) + +// Log contains actual log content and filename. If content is gzipped Compressed will be set to true. +type Log struct { + Filename string + Content []byte + Compressed bool +} + +// ExportResponse contains all available logs +type ExportResponse struct { + Error string + Logs []Log +} + +// ExportFromBaseFile reads log file and returns its content with some meta. +// In future can be extended to dump rotated logs. +func ExportFromBaseFile(logFile string) ExportResponse { + data, err := ioutil.ReadFile(logFile) + if err != nil { + return ExportResponse{Error: fmt.Errorf("error reading file %s: %v", logFile, err).Error()} + } + return ExportResponse{Logs: []Log{ + {Filename: logFile, Compressed: false, Content: hexutil.Bytes(data)}, + }} + +} diff --git a/exportlogs/logs_test.go b/exportlogs/logs_test.go new file mode 100644 index 000000000..5fbf57823 --- /dev/null +++ b/exportlogs/logs_test.go @@ -0,0 +1,30 @@ +package exportlogs + +import ( + "fmt" + "io/ioutil" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestExportLogs(t *testing.T) { + tempf, err := ioutil.TempFile("", "test-dump-logs") + require.NoError(t, err) + logs := "first line\nsecond line\n" + n, err := fmt.Fprintf(tempf, logs) + require.NoError(t, err) + require.Equal(t, len(logs), n) + response := ExportFromBaseFile(tempf.Name()) + require.Empty(t, response.Error) + require.Len(t, response.Logs, 1) + log := response.Logs[0] + require.Equal(t, false, log.Compressed) + require.Equal(t, tempf.Name(), log.Filename) + require.Equal(t, logs, string(log.Content)) +} + +func TestExportLogsNoFileError(t *testing.T) { + response := ExportFromBaseFile("doesnt-exist") + require.Equal(t, "error reading file doesnt-exist: open doesnt-exist: no such file or directory", response.Error) +} diff --git a/lib/library.go b/lib/library.go index a7b7572a9..2c4113595 100644 --- a/lib/library.go +++ b/lib/library.go @@ -5,6 +5,7 @@ import "C" import ( "encoding/hex" "encoding/json" + "errors" "fmt" "os" "unsafe" @@ -12,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/status-im/status-go/api" + "github.com/status-im/status-go/exportlogs" "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/params" "github.com/status-im/status-go/profiling" @@ -591,3 +593,21 @@ func AppStateChange(state *C.char) { func SetSignalEventCallback(cb unsafe.Pointer) { signal.SetSignalEventCallback(cb) } + +// ExportNodeLogs reads current node log and returns content to a caller. +//export ExportNodeLogs +func ExportNodeLogs() *C.char { + node := statusBackend.StatusNode() + if node == nil { + return makeJSONResponse(errors.New("node is not running")) + } + config := node.Config() + if config == nil { + return makeJSONResponse(errors.New("config and log file are not available")) + } + data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile)) + if err != nil { + return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err)) + } + return C.CString(string(data)) +} diff --git a/mobile/status.go b/mobile/status.go index b8c63af1b..84f17a781 100644 --- a/mobile/status.go +++ b/mobile/status.go @@ -3,6 +3,7 @@ package statusgo import ( "encoding/hex" "encoding/json" + "errors" "fmt" "os" "unsafe" @@ -10,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/status-im/status-go/api" + "github.com/status-im/status-go/exportlogs" "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/params" "github.com/status-im/status-go/profiling" @@ -584,3 +586,21 @@ func GetContactCode(identity string) string { return string(data) } + +// ExportNodeLogs reads current node log and returns content to a caller. +//export ExportNodeLogs +func ExportNodeLogs() string { + node := statusBackend.StatusNode() + if node == nil { + return makeJSONResponse(errors.New("node is not running")) + } + config := node.Config() + if config == nil { + return makeJSONResponse(errors.New("config and log file are not available")) + } + data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile)) + if err != nil { + return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err)) + } + return string(data) +}