package logger import ( "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ipfs/go-log" scribeTypes "github.com/synapsecns/sanguine/services/scribe/types" ) var logger = log.Logger("scribe") const ( // ContextCancelled is returned when the context is canceled. ContextCancelled ErrorType = iota // LivefillIndexerError is returned when the livefill indexer encounters an error. LivefillIndexerError // BackfillIndexerError is returned when an indexer backfilling a contract to the head encounters an error. BackfillIndexerError // GetLogsError is returned when the logs cannot be retrieved. GetLogsError // GetTxError is returned when the tx cannot be retrieved. GetTxError // CouldNotGetReceiptError is returned when the receipt cannot be retrieved. CouldNotGetReceiptError // GetBlockError is returned when the block cannot be retrieved. GetBlockError // BlockByNumberError is returned when the block cannot be retrieved. BlockByNumberError // StoreError is returned when data cannot be inserted into the database. StoreError // ReadError is returned when data cannot be read from the database. ReadError // TestError is returned when an error during a test occurs. TestError // EmptyGetLogsChunk is returned when a getLogs chunk is empty. EmptyGetLogsChunk // FatalScribeError is for when something goes wrong with scribe. FatalScribeError // ErroneousHeadBlock is returned when the head block is below the last indexed. ErroneousHeadBlock ) const ( // InitiatingLivefill is returned when a contract backfills and is moving to livefill. InitiatingLivefill StatusType = iota // ConcurrencyThresholdReached is returned when the concurrency threshold is reached. ConcurrencyThresholdReached // FlushingLivefillAtHead is returned when a livefill indexer is flushing at the head. FlushingLivefillAtHead // CreatingSQLStore is returned when a SQL store is being created. CreatingSQLStore // BackfillCompleted is returned when a backfill is completed. BackfillCompleted // BeginBackfillIndexing is returned when a backfill is beginning. BeginBackfillIndexing ) // ErrorType is a type of error. type ErrorType int // StatusType is a type of status for a process in scribe. type StatusType int // ReportIndexerError reports an error that occurs in an indexer. // // nolint func ReportIndexerError(err error, indexerData scribeTypes.IndexerConfig, errorType ErrorType) { // nolint:exhaustive if err == nil { logger.Errorf("Error, @DEV: NIL ERROR\n%s", unpackIndexerConfig(indexerData)) return } errStr := err.Error() // Stop cloudflare error messages from nuking readablity of logs if len(errStr) > 1000 { errStr = errStr[:1000] } switch errorType { case ContextCancelled: logger.Errorf("Context canceled for indexer. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case LivefillIndexerError: logger.Errorf("Livefill indexer failed. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case GetLogsError: logger.Errorf("Could not get logs. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case GetTxError: logger.Errorf("Could not get tx. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case CouldNotGetReceiptError: logger.Errorf("Could not get receipt. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case GetBlockError: logger.Errorf("Could not get head block. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case BlockByNumberError: logger.Errorf("Could not get block header. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case StoreError: logger.Errorf("Could not store data into database. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case ReadError: logger.Errorf("Could not read data from database. Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) case EmptyGetLogsChunk: logger.Warnf("Encountered empty getlogs chunk%s", unpackIndexerConfig(indexerData)) case ErroneousHeadBlock: logger.Warnf("Head block is below last indexed block%s", unpackIndexerConfig(indexerData)) default: logger.Errorf("Error: %v\n%s", errStr, unpackIndexerConfig(indexerData)) } } // ReportScribeError reports an error that occurs anywhere in scribe. // // nolint:exhaustive func ReportScribeError(err error, chainID uint32, errorType ErrorType) { switch errorType { case ContextCancelled: logger.Errorf("Context canceled for scribe on chain %d. Error: %v", chainID, err) case GetBlockError: logger.Errorf("Could not get head block on chain %d. Error: %v", chainID, err) case TestError: logger.Errorf("Test error on chain %d. Error: %v", chainID, err) default: logger.Errorf("Error on chain %d: %v", chainID, err) } } // ReportScribeState reports a state that occurs anywhere in scribe. func ReportScribeState(chainID uint32, block uint64, addresses []common.Address, statusType StatusType) { // nolint:exhaustive switch statusType { case InitiatingLivefill: logger.Warnf("Initiating livefill on chain %d on block %d while interacting with contract %s", chainID, block, dumpAddresses(addresses)) case BackfillCompleted: logger.Warnf("Backfill completed on chain %d on block %d while interacting with contract %s", chainID, block, dumpAddresses(addresses)) case BeginBackfillIndexing: logger.Warnf("Backfill beginning on chain %d on block %d while interacting with contract %s", chainID, block, dumpAddresses(addresses)) case ConcurrencyThresholdReached: logger.Warnf("Concurrency threshold reached on chain %d on block %d while interacting with contract %s", chainID, block, dumpAddresses(addresses)) case FlushingLivefillAtHead: logger.Warnf("Flushing logs at head on chain %d", chainID) case CreatingSQLStore: logger.Warnf("Creating SQL store") default: logger.Warnf("Event on chain %d on block %d while interacting with contract %s", chainID, block, dumpAddresses(addresses)) } } func unpackIndexerConfig(indexerData scribeTypes.IndexerConfig) string { return fmt.Sprintf("Contracts: %v, GetLogsRange: %d, GetLogsBatchAmount: %d, StoreConcurrency: %d, ChainID: %d, StartHeight: %d, EndHeight: %d, ConcurrencyThreshold: %d", indexerData.Addresses, indexerData.GetLogsRange, indexerData.GetLogsBatchAmount, indexerData.StoreConcurrency, indexerData.ChainID, indexerData.StartHeight, indexerData.EndHeight, indexerData.ConcurrencyThreshold) } func dumpAddresses(addresses []common.Address) string { addressesStr := "" for i := range addresses { if i == len(addresses)-1 { addressesStr += addresses[i].String() } else { addressesStr += addresses[i].String() + ", " } } return addressesStr }