Skip to content

Commit

Permalink
feat: PRT - Suppress warning log from parser to debug on successful h…
Browse files Browse the repository at this point in the history
…ash parsing (#1702)

* Suppress warning log from parser to debug on successful hash parsing

* CR Fix: Move decision out of parser

* Wrap the error with ValueNotSetError for the ValueNotSetError.Is(err)

* CR Fix

* Fix test

---------

Co-authored-by: Omer <100387053+omerlavanet@users.noreply.github.com>
  • Loading branch information
shleikes and omerlavanet authored Nov 26, 2024
1 parent f9580df commit f7f6ddb
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 48 deletions.
6 changes: 3 additions & 3 deletions protocol/chainlib/jsonRPC_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ func TestJsonRpcChainProxy(t *testing.T) {
require.NoError(t, err)

_, err = chainFetcher.FetchBlockHashByNum(ctx, block)
actualErrMsg := "GET_BLOCK_BY_NUM Failed ParseMessageResponse {error:blockParsing - parse failed {error:invalid parser input format,"
expectedErrMsg := err.Error()[:len(actualErrMsg)]
require.Equal(t, actualErrMsg, expectedErrMsg, err.Error())
expectedErrMsg := "GET_BLOCK_BY_NUM Failed ParseMessageResponse {error:failed to parse with legacy block parser ErrMsg: blockParsing -"
actualErrMsg := err.Error()[:len(expectedErrMsg)]
require.Equal(t, expectedErrMsg, actualErrMsg, err.Error())
}

func TestAddonAndVerifications(t *testing.T) {
Expand Down
71 changes: 35 additions & 36 deletions protocol/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
sdkerrors "cosmossdk.io/errors"
"github.com/lavanet/lava/v4/protocol/chainlib/chainproxy/rpcclient"
"github.com/lavanet/lava/v4/utils"
"github.com/lavanet/lava/v4/utils/lavaslices"
pairingtypes "github.com/lavanet/lava/v4/x/pairing/types"
spectypes "github.com/lavanet/lava/v4/x/spec/types"
)
Expand Down Expand Up @@ -72,23 +73,23 @@ func ParseDefaultBlockParameter(block string) (int64, error) {
}

func parseInputWithGenericParsers(rpcInput RPCInput, genericParsers []spectypes.GenericParser) (*ParsedInput, bool) {
managedToParseRawBlock := false
managedToParse := false
if len(genericParsers) == 0 {
return nil, managedToParseRawBlock
return nil, managedToParse
}

genericParserResult, genericParserErr := ParseWithGenericParsers(rpcInput, genericParsers)
if genericParserErr != nil {
return nil, managedToParseRawBlock
return nil, managedToParse
}

_, err := genericParserResult.GetBlockHashes()
if genericParserResult.GetParserError() == "" && (err == nil || genericParserResult.GetRawParsedData() != "") {
// if we got here, there is no parser error and we successfully parsed either the block hashes or the raw parsed data
managedToParseRawBlock = true
managedToParse = true
}

return genericParserResult, managedToParseRawBlock
return genericParserResult, managedToParse
}

// ParseRawBlock attempts to parse a block from rpcInput and store it in parsedInput.
Expand Down Expand Up @@ -132,12 +133,7 @@ func parseInputWithLegacyBlockParser(rpcInput RPCInput, blockParser spectypes.Bl

result, usedDefaultValue, err := legacyParse(rpcInput, blockParser, dataSource)
if err != nil || result == nil {
return "", usedDefaultValue, utils.LavaFormatDebug("blockParsing - parse failed",
utils.LogAttr("error", err),
utils.LogAttr("result", result),
utils.LogAttr("blockParser", blockParser),
utils.LogAttr("rpcInput", rpcInput),
)
return "", usedDefaultValue, fmt.Errorf("blockParsing - parse failed. result=%v error=%w", result, err)
}

resString, ok := result[spectypes.DEFAULT_PARSED_RESULT_INDEX].(string)
Expand Down Expand Up @@ -207,11 +203,23 @@ func unquoteString(str string) string {

// This returns the parsed response after decoding
func ParseBlockHashFromReplyAndDecode(rpcInput RPCInput, resultParser spectypes.BlockParser, genericParsers []spectypes.GenericParser) (string, error) {
parsedInput, _ := parseInputWithGenericParsers(rpcInput, genericParsers)
parsedInput, parsedSuccessfully := parseInputWithGenericParsers(rpcInput, genericParsers)
if parsedInput == nil {
parsedBlockHashFromBlockParser, _, err := parseInputWithLegacyBlockParser(rpcInput, resultParser, PARSE_RESULT)
if err != nil {
return "", err
parseErrorLogLevel := utils.LAVA_LOG_WARN
if parsedSuccessfully {
// found a hash, no need to log warning later
parseErrorLogLevel = utils.LAVA_LOG_DEBUG
}

return "", utils.LavaFormatLog("failed to parse with legacy block parser", err,
lavaslices.Slice(
utils.LogAttr("rpcInput", rpcInput),
utils.LogAttr("resultParser", resultParser),
),
uint(parseErrorLogLevel),
)
}
return parseResponseByEncoding([]byte(parsedBlockHashFromBlockParser), resultParser.Encoding)
}
Expand Down Expand Up @@ -240,8 +248,10 @@ func legacyParse(rpcInput RPCInput, blockParser spectypes.BlockParser, dataSourc
case spectypes.PARSER_FUNC_PARSE_CANONICAL:
retval, err = parseCanonical(rpcInput, blockParser.ParserArg, dataSource)
case spectypes.PARSER_FUNC_PARSE_DICTIONARY:
// currently, parseDictionary does not log warnings. If it ever will, we need to pass parserOptions
retval, err = parseDictionary(rpcInput, blockParser.ParserArg, dataSource)
case spectypes.PARSER_FUNC_PARSE_DICTIONARY_OR_ORDERED:
// currently, parseDictionaryOrOrdered does not log warnings. If it ever will, we need to pass parserOptions
retval, err = parseDictionaryOrOrdered(rpcInput, blockParser.ParserArg, dataSource)
case spectypes.PARSER_FUNC_DEFAULT:
retval = parseDefault(blockParser.ParserArg)
Expand Down Expand Up @@ -544,18 +554,20 @@ func blockInterfaceToString(block interface{}) string {
func parseByArg(rpcInput RPCInput, input []string, dataSource int) ([]interface{}, error) {
// specified block is one of the direct parameters, input should be one string defining the location of the block
if len(input) != 1 {
return nil, utils.LavaFormatProduction("invalid input format, input length", nil, utils.LogAttr("input_len", strconv.Itoa(len(input))))
return nil, fmt.Errorf("invalid input format, input length: %d and needs to be 1", len(input))
}

inp := input[0]
param_index, err := strconv.ParseUint(inp, 10, 32)
if err != nil {
return nil, utils.LavaFormatProduction("invalid input format, input isn't an unsigned index", err, utils.LogAttr("input", inp))
return nil, fmt.Errorf("invalid input format, input isn't an unsigned index. input=%s error=%w", inp, err)
}

unmarshalledData, err := getDataToParse(rpcInput, dataSource)
if err != nil {
return nil, utils.LavaFormatProduction("invalid input format, data is not json", err, utils.LogAttr("data", unmarshalledData))
return nil, fmt.Errorf("invalid input format, data is not json. data=%s err=%w", unmarshalledData, err)
}

switch unmarshaledDataTyped := unmarshalledData.(type) {
case []interface{}:
if uint64(len(unmarshaledDataTyped)) <= param_index {
Expand All @@ -568,11 +580,8 @@ func parseByArg(rpcInput RPCInput, input []string, dataSource int) ([]interface{
retArr = append(retArr, blockInterfaceToString(block))
return retArr, nil
default:
// Parse by arg can be only list as we dont have the name of the height property.
return nil, utils.LavaFormatProduction("Parse type unsupported in parse by arg, only list parameters are currently supported", nil,
utils.LogAttr("params", rpcInput.GetParams()),
utils.LogAttr("request", unmarshaledDataTyped),
)
// Parse by arg can be only list as we don't have the name of the height property.
return nil, fmt.Errorf("parse type unsupported in parse by arg, only list parameters are currently supported. param=%s request=%s", rpcInput.GetParams(), unmarshaledDataTyped)
}
}

Expand Down Expand Up @@ -605,28 +614,18 @@ func parseCanonical(rpcInput RPCInput, input []string, dataSource int) ([]interf
}
blockContainer := unmarshalledDataTyped[param_index]
for _, key := range input[1:] {
// type assertion for blockcontainer
// type assertion for blockContainer
if blockContainer, ok := blockContainer.(map[string]interface{}); !ok {
return nil, utils.LavaFormatWarning("invalid parser input format, blockContainer is not map[string]interface{}", ValueNotSetError,
utils.LogAttr("params", rpcInput.GetParams()),
utils.LogAttr("method", rpcInput.GetMethod()),
utils.LogAttr("blockContainer", fmt.Sprintf("%v", blockContainer)),
utils.LogAttr("key", key),
utils.LogAttr("unmarshaledDataTyped", unmarshalledDataTyped),
)
return nil, ValueNotSetError.Wrapf("invalid parser input format, blockContainer is not map[string]interface{}. "+
"params=%v method=%v blockContainer=%v key=%s unmarshaledDataTyped=%v", rpcInput.GetParams(), rpcInput.GetMethod(), blockContainer, key, unmarshalledDataTyped)
}

// assertion for key
if container, ok := blockContainer.(map[string]interface{})[key]; ok {
blockContainer = container
} else {
return nil, utils.LavaFormatWarning("invalid parser input format, blockContainer does not have the field searched inside", ValueNotSetError,
utils.LogAttr("params", rpcInput.GetParams()),
utils.LogAttr("method", rpcInput.GetMethod()),
utils.LogAttr("blockContainer", fmt.Sprintf("%v", blockContainer)),
utils.LogAttr("key", key),
utils.LogAttr("unmarshaledDataTyped", unmarshalledDataTyped),
)
return nil, ValueNotSetError.Wrapf("invalid parser input format, blockContainer does not have the field searched inside."+
"params=%v method=%v blockContainer=%v key=%s unmarshaledDataTyped=%v", rpcInput.GetParams(), rpcInput.GetMethod(), blockContainer, key, unmarshalledDataTyped)
}
}
retArr := make([]interface{}, 0)
Expand Down
24 changes: 15 additions & 9 deletions utils/lavalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
LAVA_LOG_ERROR
LAVA_LOG_FATAL
LAVA_LOG_PANIC
LAVA_LOG_PRODUCTION
NoColor = true
)

Expand Down Expand Up @@ -226,6 +227,18 @@ func LavaFormatLog(description string, err error, attributes []Attribute, severi
zerologlog.Logger = zerologlog.Output(zerolog.ConsoleWriter{Out: os.Stderr, NoColor: NoColor, TimeFormat: time.Stamp}).Level(defaultGlobalLogLevel)
}

// depending on the build flag, this log function will log either a warning or an error.
// the purpose of this function is to fail E2E tests and not allow unexpected behavior to reach main.
// while in production some errors may occur as consumers / providers might set up their processes in the wrong way.
// in test environment we don't expect to have these errors and if they occur we would like to fail the test.
if severity == LAVA_LOG_PRODUCTION {
if ExtendedLogLevel == "production" {
severity = LAVA_LOG_WARN
} else {
severity = LAVA_LOG_ERROR
}
}

var logEvent *zerolog.Event
var rollingLoggerEvent *zerolog.Event
switch severity {
Expand Down Expand Up @@ -301,16 +314,9 @@ func LavaFormatFatal(description string, err error, attributes ...Attribute) {
LavaFormatLog(description, err, attributes, LAVA_LOG_FATAL)
}

// depending on the build flag, this log function will log either a warning or an error.
// the purpose of this function is to fail E2E tests and not allow unexpected behavior to reach main.
// while in production some errors may occur as consumers / providers might set up their processes in the wrong way.
// in test environment we dont expect to have these errors and if they occur we would like to fail the test.
// see documentation in LavaFormatLog function
func LavaFormatProduction(description string, err error, attributes ...Attribute) error {
if ExtendedLogLevel == "production" {
return LavaFormatWarning(description, err, attributes...)
} else {
return LavaFormatError(description, err, attributes...)
}
return LavaFormatLog(description, err, attributes, LAVA_LOG_PRODUCTION)
}

func LavaFormatError(description string, err error, attributes ...Attribute) error {
Expand Down

0 comments on commit f7f6ddb

Please sign in to comment.