Skip to content

Commit e08555a

Browse files
committed
Merge fix/prod-log-noise-20260901
2 parents 00f1f1d + 5537f56 commit e08555a

15 files changed

Lines changed: 215 additions & 41 deletions

‎Dockerfile‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ RUN apt-get update \
6969
ENV HOST="0.0.0.0" \
7070
PORT=12345 \
7171
WORKERS=1 \
72-
LOG_LEVEL="info" \
72+
APP_ENV="production" \
73+
LOG_LEVEL="warning" \
74+
ACCESS_LOG="false" \
7375
FORWARDED_ALLOW_IPS=""
7476

7577
EXPOSE 12345
7678

7779
# 生产环境启动命令
7880
# FORWARDED_ALLOW_IPS 默认为空:仅信任直连 IP,避免任意客户端伪造 X-Forwarded-*。
7981
# 若前面有反向代理,请显式设置为代理网段,例如 "10.0.0.0/8,172.16.0.0/12"。
80-
CMD ["sh", "-c", "exec uvicorn main:app --host \"$HOST\" --port \"$PORT\" --workers \"$WORKERS\" --log-level \"$LOG_LEVEL\" --proxy-headers --forwarded-allow-ips \"${FORWARDED_ALLOW_IPS:-}\""]
82+
CMD ["sh", "-c", "access_log_arg=--no-access-log; if [ \"${APP_ENV:-development}\" != \"production\" ] || [ \"${ACCESS_LOG:-false}\" = \"true\" ]; then access_log_arg=--access-log; fi; exec uvicorn main:app --host \"$HOST\" --port \"$PORT\" --workers \"$WORKERS\" --log-level \"$LOG_LEVEL\" \"$access_log_arg\" --proxy-headers --forwarded-allow-ips \"${FORWARDED_ALLOW_IPS:-}\""]

‎core/logger.py‎

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,60 @@
11
import logging
2+
import os
23
import sys
34

45

5-
def setup_logger():
6-
# 创建logger对象
7-
_logger = logging.getLogger('FileCodeBox')
8-
_logger.setLevel(logging.INFO)
6+
PRODUCTION_ENVIRONMENTS = {"production", "prod"}
7+
LOG_LEVELS = {
8+
"debug": logging.DEBUG,
9+
"info": logging.INFO,
10+
"warning": logging.WARNING,
11+
"error": logging.ERROR,
12+
"critical": logging.CRITICAL,
13+
}
14+
15+
16+
def is_production_environment() -> bool:
17+
environment = os.getenv("APP_ENV", "development").strip().lower()
18+
return environment in PRODUCTION_ENVIRONMENTS
19+
20+
21+
def get_log_level_name() -> str:
22+
configured_level = os.getenv("LOG_LEVEL", "").strip().lower()
23+
if configured_level in LOG_LEVELS:
24+
return configured_level
25+
return "warning" if is_production_environment() else "info"
26+
927

10-
# 创建控制台处理器
11-
console_handler = logging.StreamHandler(sys.stdout)
12-
console_handler.setLevel(logging.INFO)
28+
def get_log_level() -> int:
29+
return LOG_LEVELS[get_log_level_name()]
30+
31+
32+
def is_access_log_enabled() -> bool:
33+
configured_value = os.getenv("ACCESS_LOG")
34+
if configured_value is not None:
35+
return configured_value.strip().lower() in {"1", "true", "yes", "on"}
36+
return not is_production_environment()
37+
38+
39+
def setup_logger():
40+
_logger = logging.getLogger("FileCodeBox")
41+
level = get_log_level()
42+
_logger.setLevel(level)
43+
_logger.propagate = False
44+
45+
if not _logger.handlers:
46+
console_handler = logging.StreamHandler(sys.stdout)
47+
_logger.addHandler(console_handler)
48+
else:
49+
console_handler = _logger.handlers[0]
50+
console_handler.setLevel(level)
1351

14-
# 设置日志格式
1552
formatter = logging.Formatter(
16-
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
17-
datefmt='%Y-%m-%d %H:%M:%S'
53+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
54+
datefmt="%Y-%m-%d %H:%M:%S",
1855
)
1956
console_handler.setFormatter(formatter)
2057

21-
# 添加处理器到logger
22-
_logger.addHandler(console_handler)
23-
2458
return _logger
2559

2660

‎core/storage.py‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,14 @@ async def clean_chunks(self, upload_id: str, save_path: str):
259259
try:
260260
shutil.rmtree(chunk_dir)
261261
except Exception as e:
262-
logger.info(f"清理本地分片目录失败: {e}")
262+
logger.warning(f"清理本地分片目录失败: {e}")
263263
# 清理父级 chunks 目录(如果为空)
264264
chunks_parent = chunk_dir.parent
265265
if chunks_parent.exists() and not any(chunks_parent.iterdir()):
266266
try:
267267
chunks_parent.rmdir()
268268
except Exception as e:
269-
logger.info(f"清理 chunks 父目录失败: {e}")
269+
logger.warning(f"清理 chunks 父目录失败: {e}")
270270

271271
async def file_exists(self, save_path: str) -> bool:
272272
"""
@@ -537,7 +537,7 @@ async def clean_chunks(self, upload_id: str, save_path: str):
537537
Delete={'Objects': delete_objects}
538538
)
539539
except Exception as e:
540-
logger.info(f"清理 S3 分片数据时出错: {e}")
540+
logger.warning(f"清理 S3 分片数据时出错: {e}")
541541

542542
async def generate_presigned_upload_url(self, save_path: str, expires_in: int = 900) -> Optional[str]:
543543
"""
@@ -865,7 +865,7 @@ async def clean_chunks(self, upload_id: str, save_path: str):
865865
try:
866866
await asyncio.to_thread(self._delete_chunk_dir, chunk_dir)
867867
except Exception as e:
868-
logger.info(f"清理 OneDrive 分片时出错: {e}")
868+
logger.warning(f"清理 OneDrive 分片时出错: {e}")
869869

870870
def _file_exists(self, save_path: str) -> bool:
871871
"""同步检查文件是否存在"""
@@ -1023,7 +1023,7 @@ async def clean_chunks(self, upload_id: str, save_path: str):
10231023
# OpenDAL 支持递归删除
10241024
await self.operator.remove_all(chunk_dir)
10251025
except Exception as e:
1026-
logger.info(f"清理 OpenDAL 分片时出错: {e}")
1026+
logger.warning(f"清理 OpenDAL 分片时出错: {e}")
10271027

10281028
async def file_exists(self, save_path: str) -> bool:
10291029
"""
@@ -1334,16 +1334,16 @@ async def clean_chunks(self, upload_id: str, save_path: str):
13341334
file_url = self._build_url(file_path)
13351335
async with session.delete(file_url) as delete_resp:
13361336
if delete_resp.status not in (200, 204, 404):
1337-
logger.info(f"删除分片文件失败: {file_path}")
1337+
logger.warning(f"删除分片文件失败: {file_path}")
13381338

13391339
# 删除分片目录
13401340
async with session.delete(chunk_dir_url) as delete_resp:
13411341
if delete_resp.status not in (200, 204, 404):
1342-
logger.info(f"删除分片目录失败: {chunk_dir_url}")
1342+
logger.warning(f"删除分片目录失败: {chunk_dir_url}")
13431343
else:
13441344
logger.info(f"分片目录不存在: {chunk_dir_url}")
13451345
except Exception as e:
1346-
logger.info(f"清理 WebDAV 分片时出错: {e}")
1346+
logger.warning(f"清理 WebDAV 分片时出错: {e}")
13471347

13481348
async def file_exists(self, save_path: str) -> bool:
13491349
"""

‎core/tasks.py‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# @Software: PyCharm
55
import asyncio
66
import datetime
7-
import logging
87
import os
98

109
from tortoise.expressions import Q
@@ -17,6 +16,7 @@
1716
)
1817
from apps.base.utils import ip_limit, get_chunk_file_path_name
1918
from core.config import refresh_settings
19+
from core.logger import logger
2020
from core.settings import settings, data_root
2121
from core.storage import FileStorageInterface, storages
2222
from core.utils import get_now
@@ -43,13 +43,13 @@ async def delete_expire_files():
4343
try:
4444
await file_storage.delete_file(exp)
4545
except Exception as e:
46-
logging.error(f"删除过期文件失败 code={exp.code}: {e}")
46+
logger.error(f"删除过期文件失败 code={exp.code}: {e}")
4747
try:
4848
await exp.delete()
4949
except Exception as e:
50-
logging.error(f"删除记录失败 code={exp.code}: {e}")
50+
logger.error(f"删除记录失败 code={exp.code}: {e}")
5151
except Exception as e:
52-
logging.error(e)
52+
logger.error(e)
5353
finally:
5454
await asyncio.sleep(600)
5555

@@ -75,7 +75,7 @@ async def clean_incomplete_uploads():
7575
)
7676
await file_storage.clean_chunks(session.upload_id, save_path)
7777
except Exception as e:
78-
logging.error(
78+
logger.error(
7979
f"清理分片文件失败 upload_id={session.upload_id}: {e}"
8080
)
8181

@@ -84,14 +84,14 @@ async def clean_incomplete_uploads():
8484
await StorageReservation.filter(
8585
token=f"chunk:{session.upload_id}"
8686
).delete()
87-
logging.info(f"已清理过期上传会话 upload_id={session.upload_id}")
87+
logger.info(f"已清理过期上传会话 upload_id={session.upload_id}")
8888
except Exception as e:
89-
logging.error(
89+
logger.error(
9090
f"删除分片记录失败 upload_id={session.upload_id}: {e}"
9191
)
9292

9393
except Exception as e:
94-
logging.error(f"清理未完成上传任务异常: {e}")
94+
logger.error(f"清理未完成上传任务异常: {e}")
9595
finally:
9696
await asyncio.sleep(3600)
9797

@@ -116,7 +116,7 @@ async def clean_expired_presign_sessions():
116116
)
117117
)
118118
except Exception as e:
119-
logging.error(
119+
logger.error(
120120
"清理过期直传文件失败 "
121121
f"upload_id={session.upload_id}: {e}"
122122
)
@@ -125,6 +125,6 @@ async def clean_expired_presign_sessions():
125125
).delete()
126126
await session.delete()
127127
except Exception as e:
128-
logging.error(f"清理过期预签名会话异常: {e}")
128+
logger.error(f"清理过期预签名会话异常: {e}")
129129
finally:
130130
await asyncio.sleep(900)

‎docker-compose.yml‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ services:
77
restart: unless-stopped
88
ports:
99
- "12345:12345"
10+
environment:
11+
- APP_ENV=production
12+
- LOG_LEVEL=warning
13+
- ACCESS_LOG=false
14+
- WORKERS=1
15+
logging:
16+
driver: json-file
17+
options:
18+
max-size: "10m"
19+
max-file: "3"
1020
volumes:
1121
fcb-data:
1222
external: false

‎docs/en/guide/getting-started.md‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ FileCodeBox is a simple and efficient file sharing tool that supports temporary
2121
docker run -d --restart unless-stopped \
2222
-p 12345:12345 \
2323
-v fcb-data:/app/data \
24+
-e APP_ENV=production \
25+
-e LOG_LEVEL=warning \
26+
--log-opt max-size=10m \
27+
--log-opt max-file=3 \
2428
--name filecodebox \
2529
lanol/filecodebox:latest
2630
```
@@ -32,7 +36,11 @@ The named volume persists configuration and uploaded files across container upgr
3236
| `HOST` | `0.0.0.0` | Service listening address |
3337
| `PORT` | `12345` | Service port |
3438
| `WORKERS` | `1` | Worker count; keep one worker for SQLite deployments |
35-
| `LOG_LEVEL` | `info` | `debug`, `info`, `warning`, or `error` |
39+
| `APP_ENV` | `production` (Docker) | Runtime environment; production disables HTTP access logs by default |
40+
| `LOG_LEVEL` | `warning` (Docker) | `debug`, `info`, `warning`, or `error` |
41+
| `ACCESS_LOG` | `false` (production) | Enable HTTP access logs; set to `true` when debugging requests |
42+
43+
Production deployments output only warning, error, and other key events by default. Docker retains at most three 10 MB log files.
3644

3745
### Manual Deployment
3846

‎docs/en/guide/introduction.md‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,15 @@ Command-line download
136136
### Docker Deployment
137137

138138
```bash
139-
docker run -d --restart unless-stopped -p 12345:12345 -v fcb-data:/app/data --name filecodebox lanol/filecodebox:latest
139+
docker run -d --restart unless-stopped \
140+
-p 12345:12345 \
141+
-v fcb-data:/app/data \
142+
-e APP_ENV=production \
143+
-e LOG_LEVEL=warning \
144+
--log-opt max-size=10m \
145+
--log-opt max-file=3 \
146+
--name filecodebox \
147+
lanol/filecodebox:latest
140148
```
141149

142150
### Manual Deployment

‎docs/en/index.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ features:
3737
docker run -d --restart unless-stopped \
3838
-p 12345:12345 \
3939
-v ./data:/app/data \
40+
-e APP_ENV=production \
41+
-e LOG_LEVEL=warning \
42+
--log-opt max-size=10m \
43+
--log-opt max-file=3 \
4044
--name filecodebox \
4145
lanol/filecodebox:2.5.5 # x-release-please-version
4246
```

‎docs/guide/getting-started.md‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ FileCodeBox 是一个简单高效的文件分享工具,支持文件临时中
2323
docker run -d --restart unless-stopped \
2424
-p 12345:12345 \
2525
-v fcb-data:/app/data \
26+
-e APP_ENV=production \
27+
-e LOG_LEVEL=warning \
28+
--log-opt max-size=10m \
29+
--log-opt max-file=3 \
2630
--name filecodebox \
2731
lanol/filecodebox:latest
2832
```
@@ -40,8 +44,15 @@ services:
4044
ports:
4145
- "12345:12345"
4246
environment:
47+
- APP_ENV=production
4348
- WORKERS=1
44-
- LOG_LEVEL=info
49+
- LOG_LEVEL=warning
50+
- ACCESS_LOG=false
51+
logging:
52+
driver: json-file
53+
options:
54+
max-size: "10m"
55+
max-file: "3"
4556
volumes:
4657
fcb-data:
4758
external: false
@@ -54,7 +65,11 @@ volumes:
5465
| `HOST` | `0.0.0.0` | 服务监听地址 |
5566
| `PORT` | `12345` | 服务端口 |
5667
| `WORKERS` | `1` | 工作进程数;SQLite 部署建议保持单进程 |
57-
| `LOG_LEVEL` | `info` | 日志级别:debug/info/warning/error |
68+
| `APP_ENV` | `production`(Docker) | 运行环境;生产环境默认关闭 HTTP 访问日志 |
69+
| `LOG_LEVEL` | `warning`(Docker) | 日志级别:debug/info/warning/error |
70+
| `ACCESS_LOG` | `false`(生产环境) | 是否启用 HTTP 访问日志;调试请求时可设为 `true` |
71+
72+
生产环境默认只输出 warning、error 等关键日志,并限制 Docker 日志最多保留 3 个 10 MB 文件。
5873

5974
#### 自定义配置示例
6075

@@ -63,8 +78,11 @@ docker run -d --restart=always \
6378
-p 12345:12345 \
6479
-v fcb-data:/app/data \
6580
-e WORKERS=1 \
81+
-e APP_ENV=production \
6682
-e LOG_LEVEL=warning \
6783
--name filecodebox \
84+
--log-opt max-size=10m \
85+
--log-opt max-file=3 \
6886
lanol/filecodebox:latest
6987
```
7088

‎docs/guide/introduction.md‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,15 @@ FileCodeBox 是一个基于 FastAPI + Vue3 开发的轻量级文件分享工具
150150
### Docker 部署
151151

152152
```bash
153-
docker run -d --restart unless-stopped -p 12345:12345 -v fcb-data:/app/data --name filecodebox lanol/filecodebox:latest
153+
docker run -d --restart unless-stopped \
154+
-p 12345:12345 \
155+
-v fcb-data:/app/data \
156+
-e APP_ENV=production \
157+
-e LOG_LEVEL=warning \
158+
--log-opt max-size=10m \
159+
--log-opt max-file=3 \
160+
--name filecodebox \
161+
lanol/filecodebox:latest
154162
```
155163

156164
### 手动部署

0 commit comments

Comments
 (0)