Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PRT - Suppress warning log from parser to debug on successful hash parsing #1702

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 68 additions & 27 deletions protocol/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

sdkerrors "cosmossdk.io/errors"
"github.com/lavanet/lava/v3/utils"
"github.com/lavanet/lava/v3/utils/lavaslices"
pairingtypes "github.com/lavanet/lava/v3/x/pairing/types"
spectypes "github.com/lavanet/lava/v3/x/spec/types"
)
Expand All @@ -34,6 +35,17 @@ type RPCInput interface {
GetID() json.RawMessage
}

type ParserOptions struct {
WarnLogOnFailedParsing bool
}

func (po *ParserOptions) shouldWarnLogOnFailedParsing() bool {
if po == nil {
return true
}
return po.WarnLogOnFailedParsing
}

func ParseDefaultBlockParameter(block string) (int64, error) {
switch block {
case "latest":
Expand Down Expand Up @@ -131,9 +143,15 @@ func ParseBlockFromParams(rpcInput RPCInput, blockParser spectypes.BlockParser,
parsedBlockInfo = NewParsedInput()
}

var parserOptions *ParserOptions
_, err := parsedBlockInfo.GetBlockHashes()
if err == nil {
// found a hash, no need to log warning later
parserOptions = &ParserOptions{WarnLogOnFailedParsing: false}
}
parsedBlockInfo.parsedBlock = func() int64 {
// first we try to parse the value with the block parser
result, err := parse(rpcInput, blockParser, PARSE_PARAMS)
result, err := parse(rpcInput, blockParser, PARSE_PARAMS, parserOptions)
if err != nil || result == nil {
utils.LavaFormatDebug("ParseBlockFromParams - parse failed",
utils.LogAttr("error", err),
Expand Down Expand Up @@ -176,7 +194,7 @@ func ParseBlockFromParams(rpcInput RPCInput, blockParser spectypes.BlockParser,

// This returns the parsed response without decoding
func ParseFromReply(rpcInput RPCInput, blockParser spectypes.BlockParser) (string, error) {
result, err := parse(rpcInput, blockParser, PARSE_RESULT)
result, err := parse(rpcInput, blockParser, PARSE_RESULT, nil)
if err != nil || result == nil {
utils.LavaFormatDebug("ParseBlockFromParams - parse failed",
utils.LogAttr("error", err),
Expand Down Expand Up @@ -220,20 +238,22 @@ func ParseFromReplyAndDecode(rpcInput RPCInput, resultParser spectypes.BlockPars
return parseResponseByEncoding([]byte(response), resultParser.Encoding)
}

func parse(rpcInput RPCInput, blockParser spectypes.BlockParser, dataSource int) ([]interface{}, error) {
func parse(rpcInput RPCInput, blockParser spectypes.BlockParser, dataSource int, parserOptions *ParserOptions) ([]interface{}, error) {
var retval []interface{}
var err error

switch blockParser.ParserFunc {
case spectypes.PARSER_FUNC_EMPTY:
return nil, nil
case spectypes.PARSER_FUNC_PARSE_BY_ARG:
retval, err = parseByArg(rpcInput, blockParser.ParserArg, dataSource)
retval, err = parseByArg(rpcInput, blockParser.ParserArg, dataSource, parserOptions)
case spectypes.PARSER_FUNC_PARSE_CANONICAL:
retval, err = parseCanonical(rpcInput, blockParser.ParserArg, dataSource)
retval, err = parseCanonical(rpcInput, blockParser.ParserArg, dataSource, parserOptions)
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 @@ -510,21 +530,28 @@ func blockInterfaceToString(block interface{}) string {
}
}

func parseByArg(rpcInput RPCInput, input []string, dataSource int) ([]interface{}, error) {
func parseByArg(rpcInput RPCInput, input []string, dataSource int, parserOptions *ParserOptions) ([]interface{}, error) {
var lavaLogSeverity uint = utils.LAVA_LOG_PRODUCTION
if !parserOptions.shouldWarnLogOnFailedParsing() {
lavaLogSeverity = utils.LAVA_LOG_DEBUG
}

// 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))))
utils.LavaFormatLog("invalid input format, input length", nil, lavaslices.Slice(utils.LogAttr("input_len", len(input))), lavaLogSeverity)
ranlavanet marked this conversation as resolved.
Show resolved Hide resolved
}

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, utils.LavaFormatLog("invalid input format, input isn't an unsigned index", err, lavaslices.Slice(utils.LogAttr("input", inp)), lavaLogSeverity)
}

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, utils.LavaFormatLog("invalid input format, data is not json", err, lavaslices.Slice(utils.LogAttr("data", unmarshalledData)), lavaLogSeverity)
}

switch unmarshaledDataTyped := unmarshalledData.(type) {
case []interface{}:
if uint64(len(unmarshaledDataTyped)) <= param_index {
Expand All @@ -537,10 +564,13 @@ 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, utils.LavaFormatLog("Parse type unsupported in parse by arg, only list parameters are currently supported", nil,
lavaslices.Slice(
utils.LogAttr("params", rpcInput.GetParams()),
utils.LogAttr("request", unmarshaledDataTyped),
),
lavaLogSeverity,
)
}
}
Expand All @@ -556,7 +586,12 @@ func parseByArg(rpcInput RPCInput, input []string, dataSource int) ([]interface{
// }
//
// should output an interface array with "wanted result" in first index 0
func parseCanonical(rpcInput RPCInput, input []string, dataSource int) ([]interface{}, error) {
func parseCanonical(rpcInput RPCInput, input []string, dataSource int, parserOptions *ParserOptions) ([]interface{}, error) {
var lavaLogSeverity uint = utils.LAVA_LOG_WARN
if !parserOptions.shouldWarnLogOnFailedParsing() {
lavaLogSeverity = utils.LAVA_LOG_DEBUG
}

unmarshalledData, err := getDataToParse(rpcInput, dataSource)
if err != nil {
return nil, fmt.Errorf("invalid input format, data is not json: %s, error: %s", unmarshalledData, err)
Expand All @@ -574,27 +609,33 @@ 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, utils.LavaFormatLog("invalid parser input format, blockContainer is not map[string]interface{}", ValueNotSetError,
lavaslices.Slice(
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),
),
lavaLogSeverity,
)
}

// 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, utils.LavaFormatLog("invalid parser input format, blockContainer does not have the field searched inside", ValueNotSetError,
lavaslices.Slice(
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),
),
lavaLogSeverity,
)
}
}
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
Loading