mirror of
https://codeberg.org/vlw/cloud-backup.git
synced 2025-09-14 10:03:40 +02:00
wip(22w10a): add logger
This commit is contained in:
parent
d9a6183d63
commit
e58bb45001
5 changed files with 78 additions and 17 deletions
14
.env.example
14
.env.example
|
@ -1,9 +1,15 @@
|
||||||
# Path to the local folder to back up
|
# (Required) Absolute path to the local folder to back up
|
||||||
SOURCE_FOLDER=""
|
SOURCE_FOLDER=""
|
||||||
# Name of the remote bucket (destination)
|
# (Required) Name of the remote bucket or container
|
||||||
TARGET_BUCKET=""
|
TARGET_BUCKET=""
|
||||||
|
|
||||||
# Cloud provider (gcs, s3, azure)
|
# (Required) Cloud provider (gcs, s3, azure)
|
||||||
SERVICE_NAME=""
|
SERVICE_NAME=""
|
||||||
# Cloud provider access string or path to key file
|
# (Required) Cloud provider access string or path to key file
|
||||||
SERVICE_KEY=""
|
SERVICE_KEY=""
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
|
||||||
|
# (Optional) Path to log file and level
|
||||||
|
LOG_FILE=""
|
||||||
|
LOG_LEVEL="WARNING"
|
|
@ -1,9 +1,24 @@
|
||||||
|
import os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
from .db import Database, dbname
|
from .db import Database, dbname
|
||||||
from .fs import FileSystem, file_exists
|
from .fs import FileSystem, file_exists
|
||||||
from .backup import Backup
|
from .backup import Backup
|
||||||
|
|
||||||
|
# Required environment variables
|
||||||
|
required_vars = (
|
||||||
|
"SOURCE_FOLDER",
|
||||||
|
"TARGET_BUCKET",
|
||||||
|
"SERVICE_NAME",
|
||||||
|
"SERVICE_KEY",
|
||||||
|
"LOG_LEVEL"
|
||||||
|
)
|
||||||
|
|
||||||
if not file_exists(".env"):
|
if not file_exists(".env"):
|
||||||
raise FileNotFoundError("Environment variable file does not exist. Copy '.env.example' to '.env'")
|
raise FileNotFoundError("Environment variable file does not exist. Copy '.env.example' to '.env'")
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
# Check that required environment variables are set
|
||||||
|
if not all(map(lambda var: os.getenv(var), required_vars)):
|
||||||
|
raise SystemExit("One or more required environment variables in '.env' have not been set")
|
|
@ -1,3 +1,6 @@
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from .cloud import Storage as StorageClient
|
from .cloud import Storage as StorageClient
|
||||||
|
@ -7,6 +10,7 @@ from . import dbname
|
||||||
class Backup(FileSystem):
|
class Backup(FileSystem):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.enable_logging()
|
||||||
|
|
||||||
self.has_change = False
|
self.has_change = False
|
||||||
|
|
||||||
|
@ -15,6 +19,37 @@ class Backup(FileSystem):
|
||||||
|
|
||||||
self.compress = self.db.get_flag("COMPRESS")
|
self.compress = self.db.get_flag("COMPRESS")
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
def enable_logging(self):
|
||||||
|
self.log = logging.getLogger(__name__)
|
||||||
|
self.log.debug("Start console logging")
|
||||||
|
log_format = logging.Formatter("[%(asctime)s][%(levelname)s]: %(name)s: %(message)s")
|
||||||
|
|
||||||
|
# Log to console
|
||||||
|
log_console = logging.StreamHandler()
|
||||||
|
log_console.setLevel(logging.INFO)
|
||||||
|
log_console.setFormatter(log_format)
|
||||||
|
|
||||||
|
self.log.addHandler(log_console)
|
||||||
|
|
||||||
|
# Log to file
|
||||||
|
log_file_path = os.getenv("LOG_FILE")
|
||||||
|
if log_file_path:
|
||||||
|
self.log.debug("Start file logging")
|
||||||
|
log_file = RotatingFileHandler(
|
||||||
|
log_file_path,
|
||||||
|
mode = "a",
|
||||||
|
maxBytes = 50 * 1024 * 1024,
|
||||||
|
backupCount = 5,
|
||||||
|
encoding = None,
|
||||||
|
delay = False
|
||||||
|
)
|
||||||
|
|
||||||
|
log_file.setLevel(os.getenv("LOG_LEVEL"))
|
||||||
|
log_file.setFormatter(log_format)
|
||||||
|
|
||||||
|
self.log.addHandler(log_file)
|
||||||
|
|
||||||
# Backup a file or folder
|
# Backup a file or folder
|
||||||
def backup_item(self, item: Union[list, str], silent: bool = True) -> bool:
|
def backup_item(self, item: Union[list, str], silent: bool = True) -> bool:
|
||||||
if isinstance(item, str):
|
if isinstance(item, str):
|
||||||
|
@ -32,31 +67,35 @@ class Backup(FileSystem):
|
||||||
|
|
||||||
self.has_change = True
|
self.has_change = True
|
||||||
|
|
||||||
print(f"⧖ | Uploading: '{item[0]}'", end="\r")
|
self.log.info(f"'{item[0]}': Uploading")
|
||||||
|
print(f"⏳ | Uploading: '{item[0]}'", end="\r")
|
||||||
|
|
||||||
blob = item
|
blob = item
|
||||||
# Upload as zip archive
|
# Upload as zip archive
|
||||||
if self.compress:
|
if self.compress:
|
||||||
|
self.log.debug(f"'{item[0]}': Compressing")
|
||||||
blob = FileSystem.zip(blob)
|
blob = FileSystem.zip(blob)
|
||||||
|
|
||||||
# Upload to cloud
|
# Upload to cloud
|
||||||
if self.cloud.upload(blob):
|
if self.cloud.upload(blob):
|
||||||
print(f"✓ | Upload sucessful: '{item[0]}'")
|
self.log.debug(f"'{item[0]}': Uploaded")
|
||||||
|
print(f"✅ | Upload successful: '{item[0]}'")
|
||||||
# Update local database
|
# Update local database
|
||||||
if not self.db.set_item(item):
|
if not self.db.set_item(item):
|
||||||
print("🛈 | Failed to update database")
|
self.log.warn(f"'{item[0]}': Failed to update database")
|
||||||
|
print("⚠️ | Failed to update database")
|
||||||
else:
|
else:
|
||||||
print(f"✕ | Upload failed: '{item[0]}'")
|
self.log.error(f"'{item[0]}': {self.cloud.error}")
|
||||||
if self.cloud.error:
|
print(f"❌ | Upload failed: '{item[0]}'")
|
||||||
print("🛈 | " + str(self.cloud.error))
|
|
||||||
|
|
||||||
|
|
||||||
# Remove temp zip
|
# Remove temp zip
|
||||||
if self.compress:
|
if self.compress:
|
||||||
FileSystem.delete(blob)
|
FileSystem.delete(blob)
|
||||||
|
|
||||||
|
# Deprecated: Run when a single item is backed up directly
|
||||||
if not silent and not self.has_change:
|
if not silent and not self.has_change:
|
||||||
print("✓ | Up to date. No changes found")
|
self.log.info("No changes found")
|
||||||
|
print("✅ | Up to date. No changes found")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -67,4 +106,5 @@ class Backup(FileSystem):
|
||||||
self.backup_item(item)
|
self.backup_item(item)
|
||||||
|
|
||||||
if not self.has_change:
|
if not self.has_change:
|
||||||
print("✓ | Up to date. No changes found")
|
self.log.info("No changes found")
|
||||||
|
print("✅ | Up to date. No changes found")
|
|
@ -27,5 +27,5 @@ class StorageClient:
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if e.response.status_code == 403:
|
if e.response.status_code == 403:
|
||||||
self.error = "Account lacks 'storage.objects.create' permissions on this bucket "
|
self.error = "Azure: Access key invalid or lacking required permissions"
|
||||||
return False
|
return False
|
|
@ -35,5 +35,5 @@ class StorageClient:
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if e.response.status_code == 403:
|
if e.response.status_code == 403:
|
||||||
self.error = "Account lacks 'storage.objects.create' permissions on this bucket "
|
self.error = "GCS: Forbidden: Account lacks 'storage.objects.create' role on target bucket"
|
||||||
return False
|
return False
|
Loading…
Add table
Reference in a new issue