From cee7e068322f0c3c65bf95aa1a13a01ce38d104f Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 3 Dec 2019 10:55:06 -0500 Subject: [PATCH] add configurable log level to exceptions, join message and description columns in error markdown table --- lbry/lbry/error/README.md | 185 ++++++++++++++++-------------- lbry/lbry/error/__init__.py | 84 ++++++++++++++ lbry/lbry/error/base.py | 2 +- lbry/lbry/error/generate.py | 20 ++-- lbry/lbry/extras/daemon/Daemon.py | 13 ++- 5 files changed, 209 insertions(+), 95 deletions(-) diff --git a/lbry/lbry/error/README.md b/lbry/lbry/error/README.md index fc1ff9f87..3fc5a411f 100644 --- a/lbry/lbry/error/README.md +++ b/lbry/lbry/error/README.md @@ -1,86 +1,99 @@ -Code | Name | Message | Comment ----:|---|---|--- -**1xx** | Initialization | **Daemon `start` and other CLI command failures (non-recoverable)** -**10x** | Client | Error codes reported by clients connecting to `lbrynet` daemon. -101 | RPCConnection | Failed to establish HTTP connection to `lbrynet`. (Is it running?) -102 | RPCUnresponsive | HTTP connection established but daemon is not responding to commands. -103 | WebSocketConnection | WebSocket connection established but daemon is not responding to commands. -104 | WebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?) -**11x** | Hardware | Enough of `lbrynet` was able to start to determine external factors causing eventual failure. -110 | OutOfSpace | Out of disk space. -111 | OutOfRAM | Out of RAM. -**12x** | Environment | Internal factors preventing `lbrynet` from bootstrapping itself. -120 | IncompatiblePython | Incompatible version of Python. -121 | IncompatibleDependency | Incompatible version of some library. -**13x** | Configuration | Configuration errors. -130 | CannotWriteConfiguration | Cannot write configuration file '{path}'. | When writing the default config fails on startup, such as due to permission issues. -131 | CannotOpenConfiguration | Cannot find provided configuration file '{path}'. | Can't open the config file user provided via command line args. -132 | CannotParseConfiguration | Failed to parse the configuration file '{path}'. | Includes the syntax error / line number to help user fix it. -133 | ConfigurationMissing | Configuration file '{path}' is missing setting that has no default / fallback. -134 | ConfigurationInvalid | Configuration file '{path}' has setting with invalid value. -**14x** | Command | Errors preparing to execute commands. -140 | CommandDoesNotExist | Command '{command}' does not exist. -141 | CommandDeprecated | Command '{command}' is deprecated. -142 | CommandInvalidArgument | Invalid arguments for command '{command}'. -143 | CommandTemporarilyUnavailable | Command '{command}' is temporarily unavailable. | Such as waiting for required components to start. -144 | CommandPermanentlyUnavailable | Command '{command}' is permanently unavailable. | such as when required component was intentionally configured not to start. -**2xx** | Networking | **Networking** -**20x** | Connectivity | General connectivity. -201 | NoInternet | No internet connection. -202 | NoUPnPSupport | Router does not support UPnP. -**21x** | WalletConnectivity | Wallet server connectivity. -210 | WalletConnection | Failed connecting to a lbryumx server. | Should normally not need to be handled higher up as `lbrynet` will retry other servers. -211 | WalletConnections | Failed connecting to all known lbryumx servers. | Will need to bubble up and require user to do something. -212 | WalletConnectionDropped | lbryumx droppped our connection. | Maybe we were being bad? -**22x** | WalletDisconnected | Wallet connection dropped. -220 | WalletServerSuspicious | Disconnected from lbryumx server due to suspicious responses. *generic* -221 | WalletServerValidation | Disconnected from lbryumx server due to SPV validation failure. -222 | WalletServerHeader | Disconnected from lbryumx server due to incorrect header received. -228 | WalletServerVersion | Disconnected from lbryumx server due to incompatible protocol version. -229 | WalletServerUnresponsive | Disconnected from lbryumx server due to unresponsiveness. -**23x** | DataConnectivity | P2P connection errors. -**24x** | DataNetwork | P2P download errors. -240 | DataDownload | Failed to download blob. *generic* -**25x** | DataUpload | P2P upload errors. -**26x** | DHTConnectivity | DHT connectivity issues. -**27x** | DHTProtocol | DHT protocol issues. -**3xx** | Blockchain | **Blockchain** -**30x** | TransactionRejection | Transaction rejected. -300 | TransactionRejected | Transaction rejected, unknown reason. -301 | TransactionFeeTooLow | Fee too low. -302 | TransactionInvalidSignature | Invalid signature. -**31x** | Balance | Errors related to your available balance. -311 | InsufficientFunds | Insufficient funds. | determined by wallet prior to attempting to broadcast a tx; this is different for example from a TX being created and sent but then rejected by lbrycrd for unspendable utxos. -**32x** | ChannelSigning | Channel signing. -320 | ChannelKeyNotFound | Channel signing key not found. -321 | ChannelKeyInvalid | Channel signing key is out of date. | For example, channel was updated but you don't have the updated key. -**33x** | GeneralResolve | Errors while resolving urls. -331 | Resolve | Failed to resolve '{url}'. -332 | ResolveTimeout | Failed to resolve '{url}' within the timeout. -**4xx** | Blob | **Blobs** -**40x** | BlobAvailability | Blob availability. -400 | BlobNotFound | Blob not found. -401 | BlobPermissionDenied | Permission denied to read blob. -402 | BlobTooBig | Blob is too big. -403 | BlobEmpty | Blob is empty. -**41x** | BlobDecryption | Decryption / Assembly -410 | BlobFailedDecryption | Failed to decrypt blob. -411 | CorruptBlob | Blobs is corrupted. -**42x** | BlobEncryption | Encrypting / Creating -420 | BlobFailedEncryption | Failed to encrypt blob. -**43x** | BlobRelated | Exceptions carried over from old error system. -431 | DownloadCancelled | Download was canceled. -432 | DownloadSDTimeout | Failed to download sd blob {download} within timeout. -433 | DownloadDataTimeout | Failed to download data blobs for sd hash {download} within timeout. -434 | InvalidStreamDescriptor | {message} -435 | InvalidData | {message} -436 | InvalidBlobHash | {message} -**5xx** | Component | **Components** -501 | ComponentStartConditionNotMet | Unresolved dependencies for: {components} -502 | ComponentsNotStarted | {message} -**6xx** | CurrencyExchange | **Currency Exchange** -601 | InvalidExchangeRateResponse | Failed to get exchange rate from {source}: {reason} -602 | CurrencyConversion | {message} -603 | InvalidCurrency | Invalid currency: {currency} is not a supported currency. -**7xx** | Purchase | Purchase process errors. -701 | KeyFeeAboveMaxAllowed | {message} \ No newline at end of file +# LBRY Exceptions + +Exceptions in LBRY are defined and generated from the Markdown table below. + +Column | Meaning +---|--- +Code | Codes are used only to define the hierarchy of exceptions and do not end up in the generated output, it is okay to re-number things as necessary to achieve the desired hierarchy. +Log | Log numbers map to the Python Logging Levels and specify at what log level a particular exception should be logged. For example, a Log of "4" would be ERROR log level. +Name | Generated class name for the error with "Error" appended to the end. +Message | User friendly error message explaining the error and possible solutions. + +## Error Table + +Code | Log | Name | Message +---:|---:|---|--- +**1xx** |5| Initialization | **Daemon `start` and other CLI command failures (non-recoverable)** +**10x** |5| Client | Error codes reported by clients connecting to `lbrynet` daemon. +101 |5| RPCConnection | Failed to establish HTTP connection to `lbrynet`. (Is it running?) +102 |5| RPCUnresponsive | HTTP connection established but daemon is not responding to commands. +103 |5| WebSocketConnection | WebSocket connection established but daemon is not responding to commands. +104 |5| WebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?) +**11x** |5| Hardware | Enough of `lbrynet` was able to start to determine external factors causing eventual failure. +110 |5| OutOfSpace | Out of disk space. +111 |5| OutOfRAM | Out of RAM. +**12x** |5| Environment | Internal factors preventing `lbrynet` from bootstrapping itself. +120 |5| IncompatiblePython | Incompatible version of Python. +121 |5| IncompatibleDependency | Incompatible version of some library. +**13x** |5| Configuration | Configuration errors. +130 |5| CannotWriteConfiguration | Cannot write configuration file '{path}'. -- When writing the default config fails on startup, such as due to permission issues. +131 |5| CannotOpenConfiguration | Cannot find provided configuration file '{path}'. -- Can't open the config file user provided via command line args. +132 |5| CannotParseConfiguration | Failed to parse the configuration file '{path}'. -- Includes the syntax error / line number to help user fix it. +133 |5| ConfigurationMissing | Configuration file '{path}' is missing setting that has no default / fallback. +134 |5| ConfigurationInvalid | Configuration file '{path}' has setting with invalid value. +**14x** |5| Command | Errors preparing to execute commands. +140 |5| CommandDoesNotExist | Command '{command}' does not exist. +141 |5| CommandDeprecated | Command '{command}' is deprecated. +142 |5| CommandInvalidArgument | Invalid arguments for command '{command}'. +143 |5| CommandTemporarilyUnavailable | Command '{command}' is temporarily unavailable. -- Such as waiting for required components to start. +144 |5| CommandPermanentlyUnavailable | Command '{command}' is permanently unavailable. -- such as when required component was intentionally configured not to start. +**2xx** |5| Networking | **Networking** +**20x** |5| Connectivity | General connectivity. +201 |5| NoInternet | No internet connection. +202 |5| NoUPnPSupport | Router does not support UPnP. +**21x** |5| WalletConnectivity | Wallet server connectivity. +210 |5| WalletConnection | Failed connecting to a lbryumx server. -- Should normally not need to be handled higher up as `lbrynet` will retry other servers. +211 |5| WalletConnections | Failed connecting to all known lbryumx servers. -- Will need to bubble up and require user to do something. +212 |5| WalletConnectionDropped | lbryumx droppped our connection. -- Maybe we were being bad? +**22x** |5| WalletDisconnected | Wallet connection dropped. +220 |5| WalletServerSuspicious | Disconnected from lbryumx server due to suspicious responses. *generic* +221 |5| WalletServerValidation | Disconnected from lbryumx server due to SPV validation failure. +222 |5| WalletServerHeader | Disconnected from lbryumx server due to incorrect header received. +228 |5| WalletServerVersion | Disconnected from lbryumx server due to incompatible protocol version. +229 |5| WalletServerUnresponsive | Disconnected from lbryumx server due to unresponsiveness. +**23x** |5| DataConnectivity | P2P connection errors. +**24x** |5| DataNetwork | P2P download errors. +240 |5| DataDownload | Failed to download blob. *generic* +**25x** |5| DataUpload | P2P upload errors. +**26x** |5| DHTConnectivity | DHT connectivity issues. +**27x** |5| DHTProtocol | DHT protocol issues. +**3xx** |5| Blockchain | **Blockchain** +**30x** |5| TransactionRejection | Transaction rejected. +300 |5| TransactionRejected | Transaction rejected, unknown reason. +301 |5| TransactionFeeTooLow | Fee too low. +302 |5| TransactionInvalidSignature | Invalid signature. +**31x** |5| Balance | Errors related to your available balance. +311 |5| InsufficientFunds | Insufficient funds. -- determined by wallet prior to attempting to broadcast a tx; this is different for example from a TX being created and sent but then rejected by lbrycrd for unspendable utxos. +**32x** |5| ChannelSigning | Channel signing. +320 |5| ChannelKeyNotFound | Channel signing key not found. +321 |5| ChannelKeyInvalid | Channel signing key is out of date. -- For example, channel was updated but you don't have the updated key. +**33x** |5| GeneralResolve | Errors while resolving urls. +331 |5| Resolve | Failed to resolve '{url}'. +332 |5| ResolveTimeout | Failed to resolve '{url}' within the timeout. +**4xx** |5| Blob | **Blobs** +**40x** |5| BlobAvailability | Blob availability. +400 |5| BlobNotFound | Blob not found. +401 |5| BlobPermissionDenied | Permission denied to read blob. +402 |5| BlobTooBig | Blob is too big. +403 |5| BlobEmpty | Blob is empty. +**41x** |5| BlobDecryption | Decryption / Assembly +410 |5| BlobFailedDecryption | Failed to decrypt blob. +411 |5| CorruptBlob | Blobs is corrupted. +**42x** |5| BlobEncryption | Encrypting / Creating +420 |5| BlobFailedEncryption | Failed to encrypt blob. +**43x** |5| BlobRelated | Exceptions carried over from old error system. +431 |5| DownloadCancelled | Download was canceled. +432 |5| DownloadSDTimeout | Failed to download sd blob {download} within timeout. +433 |5| DownloadDataTimeout | Failed to download data blobs for sd hash {download} within timeout. +434 |5| InvalidStreamDescriptor | {message} +435 |5| InvalidData | {message} +436 |5| InvalidBlobHash | {message} +**5xx** |5| Component | **Components** +501 |5| ComponentStartConditionNotMet | Unresolved dependencies for: {components} +502 |5| ComponentsNotStarted | {message} +**6xx** |5| CurrencyExchange | **Currency Exchange** +601 |5| InvalidExchangeRateResponse | Failed to get exchange rate from {source}: {reason} +602 |5| CurrencyConversion | {message} +603 |5| InvalidCurrency | Invalid currency: {currency} is not a supported currency. +**7xx** |5| Purchase | Purchase process errors. +701 |5| KeyFeeAboveMaxAllowed | {message} \ No newline at end of file diff --git a/lbry/lbry/error/__init__.py b/lbry/lbry/error/__init__.py index 14c01a1e3..dea8f8766 100644 --- a/lbry/lbry/error/__init__.py +++ b/lbry/lbry/error/__init__.py @@ -5,30 +5,36 @@ class InitializationError(BaseError): """ **Daemon `start` and other CLI command failures (non-recoverable)** """ + log_level = 50 class ClientError(InitializationError): """ Error codes reported by clients connecting to `lbrynet` daemon. """ + log_level = 50 class RPCConnectionError(ClientError): + log_level = 50 def __init__(self): super().__init__("Failed to establish HTTP connection to `lbrynet`. (Is it running?)") class RPCUnresponsiveError(ClientError): + log_level = 50 def __init__(self): super().__init__("HTTP connection established but daemon is not responding to commands.") class WebSocketConnectionError(ClientError): + log_level = 50 def __init__(self): super().__init__("WebSocket connection established but daemon is not responding to commands.") class WebSocketUnresponsiveError(ClientError): + log_level = 50 def __init__(self): super().__init__("Failed to establish WebSocket connection to `lbrynet`. (Is it running?)") @@ -37,14 +43,17 @@ class HardwareError(InitializationError): """ Enough of `lbrynet` was able to start to determine external factors causing eventual failure. """ + log_level = 50 class OutOfSpaceError(HardwareError): + log_level = 50 def __init__(self): super().__init__("Out of disk space.") class OutOfRAMError(HardwareError): + log_level = 50 def __init__(self): super().__init__("Out of RAM.") @@ -53,14 +62,17 @@ class EnvironmentError(InitializationError): """ Internal factors preventing `lbrynet` from bootstrapping itself. """ + log_level = 50 class IncompatiblePythonError(EnvironmentError): + log_level = 50 def __init__(self): super().__init__("Incompatible version of Python.") class IncompatibleDependencyError(EnvironmentError): + log_level = 50 def __init__(self): super().__init__("Incompatible version of some library.") @@ -69,12 +81,14 @@ class ConfigurationError(InitializationError): """ Configuration errors. """ + log_level = 50 class CannotWriteConfigurationError(ConfigurationError): """ When writing the default config fails on startup, such as due to permission issues. """ + log_level = 50 def __init__(self, path): super().__init__(f"Cannot write configuration file '{path}'.") @@ -83,6 +97,7 @@ class CannotOpenConfigurationError(ConfigurationError): """ Can't open the config file user provided via command line args. """ + log_level = 50 def __init__(self, path): super().__init__(f"Cannot find provided configuration file '{path}'.") @@ -91,16 +106,19 @@ class CannotParseConfigurationError(ConfigurationError): """ Includes the syntax error / line number to help user fix it. """ + log_level = 50 def __init__(self, path): super().__init__(f"Failed to parse the configuration file '{path}'.") class ConfigurationMissingError(ConfigurationError): + log_level = 50 def __init__(self, path): super().__init__(f"Configuration file '{path}' is missing setting that has no default / fallback.") class ConfigurationInvalidError(ConfigurationError): + log_level = 50 def __init__(self, path): super().__init__(f"Configuration file '{path}' has setting with invalid value.") @@ -109,19 +127,23 @@ class CommandError(InitializationError): """ Errors preparing to execute commands. """ + log_level = 50 class CommandDoesNotExistError(CommandError): + log_level = 50 def __init__(self, command): super().__init__(f"Command '{command}' does not exist.") class CommandDeprecatedError(CommandError): + log_level = 50 def __init__(self, command): super().__init__(f"Command '{command}' is deprecated.") class CommandInvalidArgumentError(CommandError): + log_level = 50 def __init__(self, command): super().__init__(f"Invalid arguments for command '{command}'.") @@ -130,6 +152,7 @@ class CommandTemporarilyUnavailableError(CommandError): """ Such as waiting for required components to start. """ + log_level = 50 def __init__(self, command): super().__init__(f"Command '{command}' is temporarily unavailable.") @@ -138,6 +161,7 @@ class CommandPermanentlyUnavailableError(CommandError): """ such as when required component was intentionally configured not to start. """ + log_level = 50 def __init__(self, command): super().__init__(f"Command '{command}' is permanently unavailable.") @@ -146,20 +170,24 @@ class NetworkingError(BaseError): """ **Networking** """ + log_level = 50 class ConnectivityError(NetworkingError): """ General connectivity. """ + log_level = 50 class NoInternetError(ConnectivityError): + log_level = 50 def __init__(self): super().__init__("No internet connection.") class NoUPnPSupportError(ConnectivityError): + log_level = 50 def __init__(self): super().__init__("Router does not support UPnP.") @@ -168,12 +196,14 @@ class WalletConnectivityError(NetworkingError): """ Wallet server connectivity. """ + log_level = 50 class WalletConnectionError(WalletConnectivityError): """ Should normally not need to be handled higher up as `lbrynet` will retry other servers. """ + log_level = 50 def __init__(self): super().__init__("Failed connecting to a lbryumx server.") @@ -182,6 +212,7 @@ class WalletConnectionsError(WalletConnectivityError): """ Will need to bubble up and require user to do something. """ + log_level = 50 def __init__(self): super().__init__("Failed connecting to all known lbryumx servers.") @@ -190,6 +221,7 @@ class WalletConnectionDroppedError(WalletConnectivityError): """ Maybe we were being bad? """ + log_level = 50 def __init__(self): super().__init__("lbryumx droppped our connection.") @@ -198,29 +230,35 @@ class WalletDisconnectedError(NetworkingError): """ Wallet connection dropped. """ + log_level = 50 class WalletServerSuspiciousError(WalletDisconnectedError): + log_level = 50 def __init__(self): super().__init__("Disconnected from lbryumx server due to suspicious responses. *generic*") class WalletServerValidationError(WalletDisconnectedError): + log_level = 50 def __init__(self): super().__init__("Disconnected from lbryumx server due to SPV validation failure.") class WalletServerHeaderError(WalletDisconnectedError): + log_level = 50 def __init__(self): super().__init__("Disconnected from lbryumx server due to incorrect header received.") class WalletServerVersionError(WalletDisconnectedError): + log_level = 50 def __init__(self): super().__init__("Disconnected from lbryumx server due to incompatible protocol version.") class WalletServerUnresponsiveError(WalletDisconnectedError): + log_level = 50 def __init__(self): super().__init__("Disconnected from lbryumx server due to unresponsiveness.") @@ -229,15 +267,18 @@ class DataConnectivityError(NetworkingError): """ P2P connection errors. """ + log_level = 50 class DataNetworkError(NetworkingError): """ P2P download errors. """ + log_level = 50 class DataDownloadError(DataNetworkError): + log_level = 50 def __init__(self): super().__init__("Failed to download blob. *generic*") @@ -246,43 +287,51 @@ class DataUploadError(NetworkingError): """ P2P upload errors. """ + log_level = 50 class DHTConnectivityError(NetworkingError): """ DHT connectivity issues. """ + log_level = 50 class DHTProtocolError(NetworkingError): """ DHT protocol issues. """ + log_level = 50 class BlockchainError(BaseError): """ **Blockchain** """ + log_level = 50 class TransactionRejectionError(BlockchainError): """ Transaction rejected. """ + log_level = 50 class TransactionRejectedError(TransactionRejectionError): + log_level = 50 def __init__(self): super().__init__("Transaction rejected, unknown reason.") class TransactionFeeTooLowError(TransactionRejectionError): + log_level = 50 def __init__(self): super().__init__("Fee too low.") class TransactionInvalidSignatureError(TransactionRejectionError): + log_level = 50 def __init__(self): super().__init__("Invalid signature.") @@ -291,6 +340,7 @@ class BalanceError(BlockchainError): """ Errors related to your available balance. """ + log_level = 50 class InsufficientFundsError(BalanceError): @@ -298,6 +348,7 @@ class InsufficientFundsError(BalanceError): determined by wallet prior to attempting to broadcast a tx; this is different for example from a TX being created and sent but then rejected by lbrycrd for unspendable utxos. """ + log_level = 50 def __init__(self): super().__init__("Insufficient funds.") @@ -306,9 +357,11 @@ class ChannelSigningError(BlockchainError): """ Channel signing. """ + log_level = 50 class ChannelKeyNotFoundError(ChannelSigningError): + log_level = 50 def __init__(self): super().__init__("Channel signing key not found.") @@ -317,6 +370,7 @@ class ChannelKeyInvalidError(ChannelSigningError): """ For example, channel was updated but you don't have the updated key. """ + log_level = 50 def __init__(self): super().__init__("Channel signing key is out of date.") @@ -325,14 +379,17 @@ class GeneralResolveError(BlockchainError): """ Errors while resolving urls. """ + log_level = 50 class ResolveError(GeneralResolveError): + log_level = 50 def __init__(self, url): super().__init__(f"Failed to resolve '{url}'.") class ResolveTimeoutError(GeneralResolveError): + log_level = 50 def __init__(self, url): super().__init__(f"Failed to resolve '{url}' within the timeout.") @@ -341,30 +398,36 @@ class BlobError(BaseError): """ **Blobs** """ + log_level = 50 class BlobAvailabilityError(BlobError): """ Blob availability. """ + log_level = 50 class BlobNotFoundError(BlobAvailabilityError): + log_level = 50 def __init__(self): super().__init__("Blob not found.") class BlobPermissionDeniedError(BlobAvailabilityError): + log_level = 50 def __init__(self): super().__init__("Permission denied to read blob.") class BlobTooBigError(BlobAvailabilityError): + log_level = 50 def __init__(self): super().__init__("Blob is too big.") class BlobEmptyError(BlobAvailabilityError): + log_level = 50 def __init__(self): super().__init__("Blob is empty.") @@ -373,14 +436,17 @@ class BlobDecryptionError(BlobError): """ Decryption / Assembly """ + log_level = 50 class BlobFailedDecryptionError(BlobDecryptionError): + log_level = 50 def __init__(self): super().__init__("Failed to decrypt blob.") class CorruptBlobError(BlobDecryptionError): + log_level = 50 def __init__(self): super().__init__("Blobs is corrupted.") @@ -389,9 +455,11 @@ class BlobEncryptionError(BlobError): """ Encrypting / Creating """ + log_level = 50 class BlobFailedEncryptionError(BlobEncryptionError): + log_level = 50 def __init__(self): super().__init__("Failed to encrypt blob.") @@ -400,34 +468,41 @@ class BlobRelatedError(BlobError): """ Exceptions carried over from old error system. """ + log_level = 50 class DownloadCancelledError(BlobRelatedError): + log_level = 50 def __init__(self): super().__init__("Download was canceled.") class DownloadSDTimeoutError(BlobRelatedError): + log_level = 50 def __init__(self, download): super().__init__(f"Failed to download sd blob {download} within timeout.") class DownloadDataTimeoutError(BlobRelatedError): + log_level = 50 def __init__(self, download): super().__init__(f"Failed to download data blobs for sd hash {download} within timeout.") class InvalidStreamDescriptorError(BlobRelatedError): + log_level = 50 def __init__(self, message): super().__init__(f"{message}") class InvalidDataError(BlobRelatedError): + log_level = 50 def __init__(self, message): super().__init__(f"{message}") class InvalidBlobHashError(BlobRelatedError): + log_level = 50 def __init__(self, message): super().__init__(f"{message}") @@ -436,14 +511,17 @@ class ComponentError(BaseError): """ **Components** """ + log_level = 50 class ComponentStartConditionNotMetError(ComponentError): + log_level = 50 def __init__(self, components): super().__init__(f"Unresolved dependencies for: {components}") class ComponentsNotStartedError(ComponentError): + log_level = 50 def __init__(self, message): super().__init__(f"{message}") @@ -452,19 +530,23 @@ class CurrencyExchangeError(BaseError): """ **Currency Exchange** """ + log_level = 50 class InvalidExchangeRateResponseError(CurrencyExchangeError): + log_level = 50 def __init__(self, source, reason): super().__init__(f"Failed to get exchange rate from {source}: {reason}") class CurrencyConversionError(CurrencyExchangeError): + log_level = 50 def __init__(self, message): super().__init__(f"{message}") class InvalidCurrencyError(CurrencyExchangeError): + log_level = 50 def __init__(self, currency): super().__init__(f"Invalid currency: {currency} is not a supported currency.") @@ -473,9 +555,11 @@ class PurchaseError(BaseError): """ Purchase process errors. """ + log_level = 50 class KeyFeeAboveMaxAllowedError(PurchaseError): + log_level = 50 def __init__(self, message): super().__init__(f"{message}") diff --git a/lbry/lbry/error/base.py b/lbry/lbry/error/base.py index 1d2f0f30a..6d0971e7d 100644 --- a/lbry/lbry/error/base.py +++ b/lbry/lbry/error/base.py @@ -1,2 +1,2 @@ class BaseError(Exception): - pass + log_level = 50 diff --git a/lbry/lbry/error/generate.py b/lbry/lbry/error/generate.py index 29b8ea728..cb8480c79 100644 --- a/lbry/lbry/error/generate.py +++ b/lbry/lbry/error/generate.py @@ -4,6 +4,7 @@ from textwrap import fill, indent CLASS = """ class {name}Error({parent}Error):{doc} + log_level = {log_level} """ INIT = """\ @@ -16,20 +17,25 @@ INDENT = ' ' * 4 def main(): with open('README.md', 'r') as readme: + lines = readme.readlines() + for line in lines: + if line.startswith('## Error Table'): + break print('from .base import BaseError\n') stack = {} started = False - for line in readme.readlines(): + for line in lines: if not started: started = line.startswith('---:|') continue if not line: break parent = 'Base' - columns = [c.strip() for c in line.split('|')] - (h, code, desc), comment = columns[:3], "" - if len(columns) == 4: - comment = columns[3].strip() + h, log_level, code, desc = [c.strip() for c in line.split('|')] + comment = "" + if '--' in desc: + desc, comment = [s.strip() for s in desc.split('--')] + log_level += "0" if h.startswith('**'): if h.count('x') == 1: parent = stack[h[2:3]][0] @@ -37,7 +43,7 @@ def main(): if h.count('x') == 2: stack[h.replace('**', '').replace('x', '')+'0'] = (code, desc) comment = f'\n{INDENT}"""\n{indent(fill(comment or desc, 100), INDENT)}\n{INDENT}"""' - print(CLASS.format(name=code, parent=parent, doc=comment)) + print(CLASS.format(name=code, parent=parent, doc=comment, log_level=log_level)) continue parent = stack[h[:2]][0] args = ['self'] @@ -49,7 +55,7 @@ def main(): if comment: comment = f'\n{INDENT}"""\n{indent(fill(comment, 100), INDENT)}\n{INDENT}"""' print((CLASS+INIT).format( - name=code, parent=parent, args=', '.join(args), + name=code, parent=parent, args=', '.join(args), log_level=log_level, desc=desc, doc=comment, format=fmt )) diff --git a/lbry/lbry/extras/daemon/Daemon.py b/lbry/lbry/extras/daemon/Daemon.py index 993c85749..f3e26c1fb 100644 --- a/lbry/lbry/extras/daemon/Daemon.py +++ b/lbry/lbry/extras/daemon/Daemon.py @@ -25,7 +25,10 @@ from lbry.conf import Config, Setting, NOT_SET from lbry.blob.blob_file import is_valid_blobhash, BlobBuffer from lbry.blob_exchange.downloader import download_blob from lbry.dht.peer import make_kademlia_peer -from lbry.error import DownloadSDTimeoutError, ComponentsNotStartedError, ComponentStartConditionNotMetError +from lbry.error import ( + BaseError, DownloadSDTimeoutError, + ComponentsNotStartedError, ComponentStartConditionNotMetError +) from lbry.extras import system_info from lbry.extras.daemon import analytics from lbry.extras.daemon.Components import WALLET_COMPONENT, DATABASE_COMPONENT, DHT_COMPONENT, BLOB_COMPONENT @@ -596,6 +599,14 @@ class Daemon(metaclass=JSONRPCServerType): except asyncio.CancelledError: log.info("cancelled API call for: %s", function_name) raise + except BaseError as e: + if log.isEnabledFor(e.log_level): + log.exception("SDK generated the following exception:") + return JSONRPCError( + f"Error calling {function_name} with args {args}\n" + str(e), + JSONRPCError.CODE_APPLICATION_ERROR, + format_exc() + ) except Exception as e: # pylint: disable=broad-except log.exception("error handling api request") return JSONRPCError(