add configurable log level to exceptions, join message and description columns in error markdown table

This commit is contained in:
Lex Berezhny 2019-12-03 10:55:06 -05:00
parent 03dff4b382
commit cee7e06832
5 changed files with 209 additions and 95 deletions

View file

@ -1,86 +1,99 @@
Code | Name | Message | Comment # LBRY Exceptions
---:|---|---|---
**1xx** | Initialization | **Daemon `start` and other CLI command failures (non-recoverable)** Exceptions in LBRY are defined and generated from the Markdown table below.
**10x** | Client | Error codes reported by clients connecting to `lbrynet` daemon.
101 | RPCConnection | Failed to establish HTTP connection to `lbrynet`. (Is it running?) Column | Meaning
102 | RPCUnresponsive | HTTP connection established but daemon is not responding to commands. ---|---
103 | WebSocketConnection | WebSocket connection established but daemon is not responding to commands. 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.
104 | WebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?) 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.
**11x** | Hardware | Enough of `lbrynet` was able to start to determine external factors causing eventual failure. Name | Generated class name for the error with "Error" appended to the end.
110 | OutOfSpace | Out of disk space. Message | User friendly error message explaining the error and possible solutions.
111 | OutOfRAM | Out of RAM.
**12x** | Environment | Internal factors preventing `lbrynet` from bootstrapping itself. ## Error Table
120 | IncompatiblePython | Incompatible version of Python.
121 | IncompatibleDependency | Incompatible version of some library. Code | Log | Name | Message
**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. **1xx** |5| Initialization | **Daemon `start` and other CLI command failures (non-recoverable)**
131 | CannotOpenConfiguration | Cannot find provided configuration file '{path}'. | Can't open the config file user provided via command line args. **10x** |5| Client | Error codes reported by clients connecting to `lbrynet` daemon.
132 | CannotParseConfiguration | Failed to parse the configuration file '{path}'. | Includes the syntax error / line number to help user fix it. 101 |5| RPCConnection | Failed to establish HTTP connection to `lbrynet`. (Is it running?)
133 | ConfigurationMissing | Configuration file '{path}' is missing setting that has no default / fallback. 102 |5| RPCUnresponsive | HTTP connection established but daemon is not responding to commands.
134 | ConfigurationInvalid | Configuration file '{path}' has setting with invalid value. 103 |5| WebSocketConnection | WebSocket connection established but daemon is not responding to commands.
**14x** | Command | Errors preparing to execute commands. 104 |5| WebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?)
140 | CommandDoesNotExist | Command '{command}' does not exist. **11x** |5| Hardware | Enough of `lbrynet` was able to start to determine external factors causing eventual failure.
141 | CommandDeprecated | Command '{command}' is deprecated. 110 |5| OutOfSpace | Out of disk space.
142 | CommandInvalidArgument | Invalid arguments for command '{command}'. 111 |5| OutOfRAM | Out of RAM.
143 | CommandTemporarilyUnavailable | Command '{command}' is temporarily unavailable. | Such as waiting for required components to start. **12x** |5| Environment | Internal factors preventing `lbrynet` from bootstrapping itself.
144 | CommandPermanentlyUnavailable | Command '{command}' is permanently unavailable. | such as when required component was intentionally configured not to start. 120 |5| IncompatiblePython | Incompatible version of Python.
**2xx** | Networking | **Networking** 121 |5| IncompatibleDependency | Incompatible version of some library.
**20x** | Connectivity | General connectivity. **13x** |5| Configuration | Configuration errors.
201 | NoInternet | No internet connection. 130 |5| CannotWriteConfiguration | Cannot write configuration file '{path}'. -- When writing the default config fails on startup, such as due to permission issues.
202 | NoUPnPSupport | Router does not support UPnP. 131 |5| CannotOpenConfiguration | Cannot find provided configuration file '{path}'. -- Can't open the config file user provided via command line args.
**21x** | WalletConnectivity | Wallet server connectivity. 132 |5| CannotParseConfiguration | Failed to parse the configuration file '{path}'. -- Includes the syntax error / line number to help user fix it.
210 | WalletConnection | Failed connecting to a lbryumx server. | Should normally not need to be handled higher up as `lbrynet` will retry other servers. 133 |5| ConfigurationMissing | Configuration file '{path}' is missing setting that has no default / fallback.
211 | WalletConnections | Failed connecting to all known lbryumx servers. | Will need to bubble up and require user to do something. 134 |5| ConfigurationInvalid | Configuration file '{path}' has setting with invalid value.
212 | WalletConnectionDropped | lbryumx droppped our connection. | Maybe we were being bad? **14x** |5| Command | Errors preparing to execute commands.
**22x** | WalletDisconnected | Wallet connection dropped. 140 |5| CommandDoesNotExist | Command '{command}' does not exist.
220 | WalletServerSuspicious | Disconnected from lbryumx server due to suspicious responses. *generic* 141 |5| CommandDeprecated | Command '{command}' is deprecated.
221 | WalletServerValidation | Disconnected from lbryumx server due to SPV validation failure. 142 |5| CommandInvalidArgument | Invalid arguments for command '{command}'.
222 | WalletServerHeader | Disconnected from lbryumx server due to incorrect header received. 143 |5| CommandTemporarilyUnavailable | Command '{command}' is temporarily unavailable. -- Such as waiting for required components to start.
228 | WalletServerVersion | Disconnected from lbryumx server due to incompatible protocol version. 144 |5| CommandPermanentlyUnavailable | Command '{command}' is permanently unavailable. -- such as when required component was intentionally configured not to start.
229 | WalletServerUnresponsive | Disconnected from lbryumx server due to unresponsiveness. **2xx** |5| Networking | **Networking**
**23x** | DataConnectivity | P2P connection errors. **20x** |5| Connectivity | General connectivity.
**24x** | DataNetwork | P2P download errors. 201 |5| NoInternet | No internet connection.
240 | DataDownload | Failed to download blob. *generic* 202 |5| NoUPnPSupport | Router does not support UPnP.
**25x** | DataUpload | P2P upload errors. **21x** |5| WalletConnectivity | Wallet server connectivity.
**26x** | DHTConnectivity | DHT connectivity issues. 210 |5| WalletConnection | Failed connecting to a lbryumx server. -- Should normally not need to be handled higher up as `lbrynet` will retry other servers.
**27x** | DHTProtocol | DHT protocol issues. 211 |5| WalletConnections | Failed connecting to all known lbryumx servers. -- Will need to bubble up and require user to do something.
**3xx** | Blockchain | **Blockchain** 212 |5| WalletConnectionDropped | lbryumx droppped our connection. -- Maybe we were being bad?
**30x** | TransactionRejection | Transaction rejected. **22x** |5| WalletDisconnected | Wallet connection dropped.
300 | TransactionRejected | Transaction rejected, unknown reason. 220 |5| WalletServerSuspicious | Disconnected from lbryumx server due to suspicious responses. *generic*
301 | TransactionFeeTooLow | Fee too low. 221 |5| WalletServerValidation | Disconnected from lbryumx server due to SPV validation failure.
302 | TransactionInvalidSignature | Invalid signature. 222 |5| WalletServerHeader | Disconnected from lbryumx server due to incorrect header received.
**31x** | Balance | Errors related to your available balance. 228 |5| WalletServerVersion | Disconnected from lbryumx server due to incompatible protocol version.
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. 229 |5| WalletServerUnresponsive | Disconnected from lbryumx server due to unresponsiveness.
**32x** | ChannelSigning | Channel signing. **23x** |5| DataConnectivity | P2P connection errors.
320 | ChannelKeyNotFound | Channel signing key not found. **24x** |5| DataNetwork | P2P download errors.
321 | ChannelKeyInvalid | Channel signing key is out of date. | For example, channel was updated but you don't have the updated key. 240 |5| DataDownload | Failed to download blob. *generic*
**33x** | GeneralResolve | Errors while resolving urls. **25x** |5| DataUpload | P2P upload errors.
331 | Resolve | Failed to resolve '{url}'. **26x** |5| DHTConnectivity | DHT connectivity issues.
332 | ResolveTimeout | Failed to resolve '{url}' within the timeout. **27x** |5| DHTProtocol | DHT protocol issues.
**4xx** | Blob | **Blobs** **3xx** |5| Blockchain | **Blockchain**
**40x** | BlobAvailability | Blob availability. **30x** |5| TransactionRejection | Transaction rejected.
400 | BlobNotFound | Blob not found. 300 |5| TransactionRejected | Transaction rejected, unknown reason.
401 | BlobPermissionDenied | Permission denied to read blob. 301 |5| TransactionFeeTooLow | Fee too low.
402 | BlobTooBig | Blob is too big. 302 |5| TransactionInvalidSignature | Invalid signature.
403 | BlobEmpty | Blob is empty. **31x** |5| Balance | Errors related to your available balance.
**41x** | BlobDecryption | Decryption / Assembly 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.
410 | BlobFailedDecryption | Failed to decrypt blob. **32x** |5| ChannelSigning | Channel signing.
411 | CorruptBlob | Blobs is corrupted. 320 |5| ChannelKeyNotFound | Channel signing key not found.
**42x** | BlobEncryption | Encrypting / Creating 321 |5| ChannelKeyInvalid | Channel signing key is out of date. -- For example, channel was updated but you don't have the updated key.
420 | BlobFailedEncryption | Failed to encrypt blob. **33x** |5| GeneralResolve | Errors while resolving urls.
**43x** | BlobRelated | Exceptions carried over from old error system. 331 |5| Resolve | Failed to resolve '{url}'.
431 | DownloadCancelled | Download was canceled. 332 |5| ResolveTimeout | Failed to resolve '{url}' within the timeout.
432 | DownloadSDTimeout | Failed to download sd blob {download} within timeout. **4xx** |5| Blob | **Blobs**
433 | DownloadDataTimeout | Failed to download data blobs for sd hash {download} within timeout. **40x** |5| BlobAvailability | Blob availability.
434 | InvalidStreamDescriptor | {message} 400 |5| BlobNotFound | Blob not found.
435 | InvalidData | {message} 401 |5| BlobPermissionDenied | Permission denied to read blob.
436 | InvalidBlobHash | {message} 402 |5| BlobTooBig | Blob is too big.
**5xx** | Component | **Components** 403 |5| BlobEmpty | Blob is empty.
501 | ComponentStartConditionNotMet | Unresolved dependencies for: {components} **41x** |5| BlobDecryption | Decryption / Assembly
502 | ComponentsNotStarted | {message} 410 |5| BlobFailedDecryption | Failed to decrypt blob.
**6xx** | CurrencyExchange | **Currency Exchange** 411 |5| CorruptBlob | Blobs is corrupted.
601 | InvalidExchangeRateResponse | Failed to get exchange rate from {source}: {reason} **42x** |5| BlobEncryption | Encrypting / Creating
602 | CurrencyConversion | {message} 420 |5| BlobFailedEncryption | Failed to encrypt blob.
603 | InvalidCurrency | Invalid currency: {currency} is not a supported currency. **43x** |5| BlobRelated | Exceptions carried over from old error system.
**7xx** | Purchase | Purchase process errors. 431 |5| DownloadCancelled | Download was canceled.
701 | KeyFeeAboveMaxAllowed | {message} 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}

View file

@ -5,30 +5,36 @@ class InitializationError(BaseError):
""" """
**Daemon `start` and other CLI command failures (non-recoverable)** **Daemon `start` and other CLI command failures (non-recoverable)**
""" """
log_level = 50
class ClientError(InitializationError): class ClientError(InitializationError):
""" """
Error codes reported by clients connecting to `lbrynet` daemon. Error codes reported by clients connecting to `lbrynet` daemon.
""" """
log_level = 50
class RPCConnectionError(ClientError): class RPCConnectionError(ClientError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed to establish HTTP connection to `lbrynet`. (Is it running?)") super().__init__("Failed to establish HTTP connection to `lbrynet`. (Is it running?)")
class RPCUnresponsiveError(ClientError): class RPCUnresponsiveError(ClientError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("HTTP connection established but daemon is not responding to commands.") super().__init__("HTTP connection established but daemon is not responding to commands.")
class WebSocketConnectionError(ClientError): class WebSocketConnectionError(ClientError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("WebSocket connection established but daemon is not responding to commands.") super().__init__("WebSocket connection established but daemon is not responding to commands.")
class WebSocketUnresponsiveError(ClientError): class WebSocketUnresponsiveError(ClientError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed to establish WebSocket connection to `lbrynet`. (Is it running?)") 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. Enough of `lbrynet` was able to start to determine external factors causing eventual failure.
""" """
log_level = 50
class OutOfSpaceError(HardwareError): class OutOfSpaceError(HardwareError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Out of disk space.") super().__init__("Out of disk space.")
class OutOfRAMError(HardwareError): class OutOfRAMError(HardwareError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Out of RAM.") super().__init__("Out of RAM.")
@ -53,14 +62,17 @@ class EnvironmentError(InitializationError):
""" """
Internal factors preventing `lbrynet` from bootstrapping itself. Internal factors preventing `lbrynet` from bootstrapping itself.
""" """
log_level = 50
class IncompatiblePythonError(EnvironmentError): class IncompatiblePythonError(EnvironmentError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Incompatible version of Python.") super().__init__("Incompatible version of Python.")
class IncompatibleDependencyError(EnvironmentError): class IncompatibleDependencyError(EnvironmentError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Incompatible version of some library.") super().__init__("Incompatible version of some library.")
@ -69,12 +81,14 @@ class ConfigurationError(InitializationError):
""" """
Configuration errors. Configuration errors.
""" """
log_level = 50
class CannotWriteConfigurationError(ConfigurationError): class CannotWriteConfigurationError(ConfigurationError):
""" """
When writing the default config fails on startup, such as due to permission issues. When writing the default config fails on startup, such as due to permission issues.
""" """
log_level = 50
def __init__(self, path): def __init__(self, path):
super().__init__(f"Cannot write configuration file '{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. Can't open the config file user provided via command line args.
""" """
log_level = 50
def __init__(self, path): def __init__(self, path):
super().__init__(f"Cannot find provided configuration file '{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. Includes the syntax error / line number to help user fix it.
""" """
log_level = 50
def __init__(self, path): def __init__(self, path):
super().__init__(f"Failed to parse the configuration file '{path}'.") super().__init__(f"Failed to parse the configuration file '{path}'.")
class ConfigurationMissingError(ConfigurationError): class ConfigurationMissingError(ConfigurationError):
log_level = 50
def __init__(self, path): def __init__(self, path):
super().__init__(f"Configuration file '{path}' is missing setting that has no default / fallback.") super().__init__(f"Configuration file '{path}' is missing setting that has no default / fallback.")
class ConfigurationInvalidError(ConfigurationError): class ConfigurationInvalidError(ConfigurationError):
log_level = 50
def __init__(self, path): def __init__(self, path):
super().__init__(f"Configuration file '{path}' has setting with invalid value.") super().__init__(f"Configuration file '{path}' has setting with invalid value.")
@ -109,19 +127,23 @@ class CommandError(InitializationError):
""" """
Errors preparing to execute commands. Errors preparing to execute commands.
""" """
log_level = 50
class CommandDoesNotExistError(CommandError): class CommandDoesNotExistError(CommandError):
log_level = 50
def __init__(self, command): def __init__(self, command):
super().__init__(f"Command '{command}' does not exist.") super().__init__(f"Command '{command}' does not exist.")
class CommandDeprecatedError(CommandError): class CommandDeprecatedError(CommandError):
log_level = 50
def __init__(self, command): def __init__(self, command):
super().__init__(f"Command '{command}' is deprecated.") super().__init__(f"Command '{command}' is deprecated.")
class CommandInvalidArgumentError(CommandError): class CommandInvalidArgumentError(CommandError):
log_level = 50
def __init__(self, command): def __init__(self, command):
super().__init__(f"Invalid arguments for command '{command}'.") super().__init__(f"Invalid arguments for command '{command}'.")
@ -130,6 +152,7 @@ class CommandTemporarilyUnavailableError(CommandError):
""" """
Such as waiting for required components to start. Such as waiting for required components to start.
""" """
log_level = 50
def __init__(self, command): def __init__(self, command):
super().__init__(f"Command '{command}' is temporarily unavailable.") 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. such as when required component was intentionally configured not to start.
""" """
log_level = 50
def __init__(self, command): def __init__(self, command):
super().__init__(f"Command '{command}' is permanently unavailable.") super().__init__(f"Command '{command}' is permanently unavailable.")
@ -146,20 +170,24 @@ class NetworkingError(BaseError):
""" """
**Networking** **Networking**
""" """
log_level = 50
class ConnectivityError(NetworkingError): class ConnectivityError(NetworkingError):
""" """
General connectivity. General connectivity.
""" """
log_level = 50
class NoInternetError(ConnectivityError): class NoInternetError(ConnectivityError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("No internet connection.") super().__init__("No internet connection.")
class NoUPnPSupportError(ConnectivityError): class NoUPnPSupportError(ConnectivityError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Router does not support UPnP.") super().__init__("Router does not support UPnP.")
@ -168,12 +196,14 @@ class WalletConnectivityError(NetworkingError):
""" """
Wallet server connectivity. Wallet server connectivity.
""" """
log_level = 50
class WalletConnectionError(WalletConnectivityError): class WalletConnectionError(WalletConnectivityError):
""" """
Should normally not need to be handled higher up as `lbrynet` will retry other servers. Should normally not need to be handled higher up as `lbrynet` will retry other servers.
""" """
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed connecting to a lbryumx server.") 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. Will need to bubble up and require user to do something.
""" """
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed connecting to all known lbryumx servers.") super().__init__("Failed connecting to all known lbryumx servers.")
@ -190,6 +221,7 @@ class WalletConnectionDroppedError(WalletConnectivityError):
""" """
Maybe we were being bad? Maybe we were being bad?
""" """
log_level = 50
def __init__(self): def __init__(self):
super().__init__("lbryumx droppped our connection.") super().__init__("lbryumx droppped our connection.")
@ -198,29 +230,35 @@ class WalletDisconnectedError(NetworkingError):
""" """
Wallet connection dropped. Wallet connection dropped.
""" """
log_level = 50
class WalletServerSuspiciousError(WalletDisconnectedError): class WalletServerSuspiciousError(WalletDisconnectedError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Disconnected from lbryumx server due to suspicious responses. *generic*") super().__init__("Disconnected from lbryumx server due to suspicious responses. *generic*")
class WalletServerValidationError(WalletDisconnectedError): class WalletServerValidationError(WalletDisconnectedError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Disconnected from lbryumx server due to SPV validation failure.") super().__init__("Disconnected from lbryumx server due to SPV validation failure.")
class WalletServerHeaderError(WalletDisconnectedError): class WalletServerHeaderError(WalletDisconnectedError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Disconnected from lbryumx server due to incorrect header received.") super().__init__("Disconnected from lbryumx server due to incorrect header received.")
class WalletServerVersionError(WalletDisconnectedError): class WalletServerVersionError(WalletDisconnectedError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Disconnected from lbryumx server due to incompatible protocol version.") super().__init__("Disconnected from lbryumx server due to incompatible protocol version.")
class WalletServerUnresponsiveError(WalletDisconnectedError): class WalletServerUnresponsiveError(WalletDisconnectedError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Disconnected from lbryumx server due to unresponsiveness.") super().__init__("Disconnected from lbryumx server due to unresponsiveness.")
@ -229,15 +267,18 @@ class DataConnectivityError(NetworkingError):
""" """
P2P connection errors. P2P connection errors.
""" """
log_level = 50
class DataNetworkError(NetworkingError): class DataNetworkError(NetworkingError):
""" """
P2P download errors. P2P download errors.
""" """
log_level = 50
class DataDownloadError(DataNetworkError): class DataDownloadError(DataNetworkError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed to download blob. *generic*") super().__init__("Failed to download blob. *generic*")
@ -246,43 +287,51 @@ class DataUploadError(NetworkingError):
""" """
P2P upload errors. P2P upload errors.
""" """
log_level = 50
class DHTConnectivityError(NetworkingError): class DHTConnectivityError(NetworkingError):
""" """
DHT connectivity issues. DHT connectivity issues.
""" """
log_level = 50
class DHTProtocolError(NetworkingError): class DHTProtocolError(NetworkingError):
""" """
DHT protocol issues. DHT protocol issues.
""" """
log_level = 50
class BlockchainError(BaseError): class BlockchainError(BaseError):
""" """
**Blockchain** **Blockchain**
""" """
log_level = 50
class TransactionRejectionError(BlockchainError): class TransactionRejectionError(BlockchainError):
""" """
Transaction rejected. Transaction rejected.
""" """
log_level = 50
class TransactionRejectedError(TransactionRejectionError): class TransactionRejectedError(TransactionRejectionError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Transaction rejected, unknown reason.") super().__init__("Transaction rejected, unknown reason.")
class TransactionFeeTooLowError(TransactionRejectionError): class TransactionFeeTooLowError(TransactionRejectionError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Fee too low.") super().__init__("Fee too low.")
class TransactionInvalidSignatureError(TransactionRejectionError): class TransactionInvalidSignatureError(TransactionRejectionError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Invalid signature.") super().__init__("Invalid signature.")
@ -291,6 +340,7 @@ class BalanceError(BlockchainError):
""" """
Errors related to your available balance. Errors related to your available balance.
""" """
log_level = 50
class InsufficientFundsError(BalanceError): 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 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. being created and sent but then rejected by lbrycrd for unspendable utxos.
""" """
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Insufficient funds.") super().__init__("Insufficient funds.")
@ -306,9 +357,11 @@ class ChannelSigningError(BlockchainError):
""" """
Channel signing. Channel signing.
""" """
log_level = 50
class ChannelKeyNotFoundError(ChannelSigningError): class ChannelKeyNotFoundError(ChannelSigningError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Channel signing key not found.") 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. For example, channel was updated but you don't have the updated key.
""" """
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Channel signing key is out of date.") super().__init__("Channel signing key is out of date.")
@ -325,14 +379,17 @@ class GeneralResolveError(BlockchainError):
""" """
Errors while resolving urls. Errors while resolving urls.
""" """
log_level = 50
class ResolveError(GeneralResolveError): class ResolveError(GeneralResolveError):
log_level = 50
def __init__(self, url): def __init__(self, url):
super().__init__(f"Failed to resolve '{url}'.") super().__init__(f"Failed to resolve '{url}'.")
class ResolveTimeoutError(GeneralResolveError): class ResolveTimeoutError(GeneralResolveError):
log_level = 50
def __init__(self, url): def __init__(self, url):
super().__init__(f"Failed to resolve '{url}' within the timeout.") super().__init__(f"Failed to resolve '{url}' within the timeout.")
@ -341,30 +398,36 @@ class BlobError(BaseError):
""" """
**Blobs** **Blobs**
""" """
log_level = 50
class BlobAvailabilityError(BlobError): class BlobAvailabilityError(BlobError):
""" """
Blob availability. Blob availability.
""" """
log_level = 50
class BlobNotFoundError(BlobAvailabilityError): class BlobNotFoundError(BlobAvailabilityError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Blob not found.") super().__init__("Blob not found.")
class BlobPermissionDeniedError(BlobAvailabilityError): class BlobPermissionDeniedError(BlobAvailabilityError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Permission denied to read blob.") super().__init__("Permission denied to read blob.")
class BlobTooBigError(BlobAvailabilityError): class BlobTooBigError(BlobAvailabilityError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Blob is too big.") super().__init__("Blob is too big.")
class BlobEmptyError(BlobAvailabilityError): class BlobEmptyError(BlobAvailabilityError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Blob is empty.") super().__init__("Blob is empty.")
@ -373,14 +436,17 @@ class BlobDecryptionError(BlobError):
""" """
Decryption / Assembly Decryption / Assembly
""" """
log_level = 50
class BlobFailedDecryptionError(BlobDecryptionError): class BlobFailedDecryptionError(BlobDecryptionError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed to decrypt blob.") super().__init__("Failed to decrypt blob.")
class CorruptBlobError(BlobDecryptionError): class CorruptBlobError(BlobDecryptionError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Blobs is corrupted.") super().__init__("Blobs is corrupted.")
@ -389,9 +455,11 @@ class BlobEncryptionError(BlobError):
""" """
Encrypting / Creating Encrypting / Creating
""" """
log_level = 50
class BlobFailedEncryptionError(BlobEncryptionError): class BlobFailedEncryptionError(BlobEncryptionError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Failed to encrypt blob.") super().__init__("Failed to encrypt blob.")
@ -400,34 +468,41 @@ class BlobRelatedError(BlobError):
""" """
Exceptions carried over from old error system. Exceptions carried over from old error system.
""" """
log_level = 50
class DownloadCancelledError(BlobRelatedError): class DownloadCancelledError(BlobRelatedError):
log_level = 50
def __init__(self): def __init__(self):
super().__init__("Download was canceled.") super().__init__("Download was canceled.")
class DownloadSDTimeoutError(BlobRelatedError): class DownloadSDTimeoutError(BlobRelatedError):
log_level = 50
def __init__(self, download): def __init__(self, download):
super().__init__(f"Failed to download sd blob {download} within timeout.") super().__init__(f"Failed to download sd blob {download} within timeout.")
class DownloadDataTimeoutError(BlobRelatedError): class DownloadDataTimeoutError(BlobRelatedError):
log_level = 50
def __init__(self, download): def __init__(self, download):
super().__init__(f"Failed to download data blobs for sd hash {download} within timeout.") super().__init__(f"Failed to download data blobs for sd hash {download} within timeout.")
class InvalidStreamDescriptorError(BlobRelatedError): class InvalidStreamDescriptorError(BlobRelatedError):
log_level = 50
def __init__(self, message): def __init__(self, message):
super().__init__(f"{message}") super().__init__(f"{message}")
class InvalidDataError(BlobRelatedError): class InvalidDataError(BlobRelatedError):
log_level = 50
def __init__(self, message): def __init__(self, message):
super().__init__(f"{message}") super().__init__(f"{message}")
class InvalidBlobHashError(BlobRelatedError): class InvalidBlobHashError(BlobRelatedError):
log_level = 50
def __init__(self, message): def __init__(self, message):
super().__init__(f"{message}") super().__init__(f"{message}")
@ -436,14 +511,17 @@ class ComponentError(BaseError):
""" """
**Components** **Components**
""" """
log_level = 50
class ComponentStartConditionNotMetError(ComponentError): class ComponentStartConditionNotMetError(ComponentError):
log_level = 50
def __init__(self, components): def __init__(self, components):
super().__init__(f"Unresolved dependencies for: {components}") super().__init__(f"Unresolved dependencies for: {components}")
class ComponentsNotStartedError(ComponentError): class ComponentsNotStartedError(ComponentError):
log_level = 50
def __init__(self, message): def __init__(self, message):
super().__init__(f"{message}") super().__init__(f"{message}")
@ -452,19 +530,23 @@ class CurrencyExchangeError(BaseError):
""" """
**Currency Exchange** **Currency Exchange**
""" """
log_level = 50
class InvalidExchangeRateResponseError(CurrencyExchangeError): class InvalidExchangeRateResponseError(CurrencyExchangeError):
log_level = 50
def __init__(self, source, reason): def __init__(self, source, reason):
super().__init__(f"Failed to get exchange rate from {source}: {reason}") super().__init__(f"Failed to get exchange rate from {source}: {reason}")
class CurrencyConversionError(CurrencyExchangeError): class CurrencyConversionError(CurrencyExchangeError):
log_level = 50
def __init__(self, message): def __init__(self, message):
super().__init__(f"{message}") super().__init__(f"{message}")
class InvalidCurrencyError(CurrencyExchangeError): class InvalidCurrencyError(CurrencyExchangeError):
log_level = 50
def __init__(self, currency): def __init__(self, currency):
super().__init__(f"Invalid currency: {currency} is not a supported currency.") super().__init__(f"Invalid currency: {currency} is not a supported currency.")
@ -473,9 +555,11 @@ class PurchaseError(BaseError):
""" """
Purchase process errors. Purchase process errors.
""" """
log_level = 50
class KeyFeeAboveMaxAllowedError(PurchaseError): class KeyFeeAboveMaxAllowedError(PurchaseError):
log_level = 50
def __init__(self, message): def __init__(self, message):
super().__init__(f"{message}") super().__init__(f"{message}")

View file

@ -1,2 +1,2 @@
class BaseError(Exception): class BaseError(Exception):
pass log_level = 50

View file

@ -4,6 +4,7 @@ from textwrap import fill, indent
CLASS = """ CLASS = """
class {name}Error({parent}Error):{doc} class {name}Error({parent}Error):{doc}
log_level = {log_level}
""" """
INIT = """\ INIT = """\
@ -16,20 +17,25 @@ INDENT = ' ' * 4
def main(): def main():
with open('README.md', 'r') as readme: 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') print('from .base import BaseError\n')
stack = {} stack = {}
started = False started = False
for line in readme.readlines(): for line in lines:
if not started: if not started:
started = line.startswith('---:|') started = line.startswith('---:|')
continue continue
if not line: if not line:
break break
parent = 'Base' parent = 'Base'
columns = [c.strip() for c in line.split('|')] h, log_level, code, desc = [c.strip() for c in line.split('|')]
(h, code, desc), comment = columns[:3], "" comment = ""
if len(columns) == 4: if '--' in desc:
comment = columns[3].strip() desc, comment = [s.strip() for s in desc.split('--')]
log_level += "0"
if h.startswith('**'): if h.startswith('**'):
if h.count('x') == 1: if h.count('x') == 1:
parent = stack[h[2:3]][0] parent = stack[h[2:3]][0]
@ -37,7 +43,7 @@ def main():
if h.count('x') == 2: if h.count('x') == 2:
stack[h.replace('**', '').replace('x', '')+'0'] = (code, desc) stack[h.replace('**', '').replace('x', '')+'0'] = (code, desc)
comment = f'\n{INDENT}"""\n{indent(fill(comment or desc, 100), INDENT)}\n{INDENT}"""' 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 continue
parent = stack[h[:2]][0] parent = stack[h[:2]][0]
args = ['self'] args = ['self']
@ -49,7 +55,7 @@ def main():
if comment: if comment:
comment = f'\n{INDENT}"""\n{indent(fill(comment, 100), INDENT)}\n{INDENT}"""' comment = f'\n{INDENT}"""\n{indent(fill(comment, 100), INDENT)}\n{INDENT}"""'
print((CLASS+INIT).format( 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 desc=desc, doc=comment, format=fmt
)) ))

View file

@ -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.blob_file import is_valid_blobhash, BlobBuffer
from lbry.blob_exchange.downloader import download_blob from lbry.blob_exchange.downloader import download_blob
from lbry.dht.peer import make_kademlia_peer 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 import system_info
from lbry.extras.daemon import analytics from lbry.extras.daemon import analytics
from lbry.extras.daemon.Components import WALLET_COMPONENT, DATABASE_COMPONENT, DHT_COMPONENT, BLOB_COMPONENT 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: except asyncio.CancelledError:
log.info("cancelled API call for: %s", function_name) log.info("cancelled API call for: %s", function_name)
raise 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 except Exception as e: # pylint: disable=broad-except
log.exception("error handling api request") log.exception("error handling api request")
return JSONRPCError( return JSONRPCError(