1
0
mirror of https://github.com/astaxie/beego.git synced 2025-04-02 20:15:58 +00:00

Compare commits

...

1195 Commits

Author SHA1 Message Date
Ming Deng
56d89cc55c
Merge pull request #8 from flycash/fix4734-1x
do not reset id to 0
2021-08-20 19:54:42 +08:00
Ming Deng
e048377594 do not reset id to 0 2021-08-20 19:53:51 +08:00
Ming Deng
34334a52be
Merge pull request #7 from flycash/fix4734-1x
Fix 4734: we don't need to reset the id to 0
2021-08-19 21:52:16 +08:00
Ming Deng
7cdf96d21a Fix 4734: we don't need to reset the id to 0 2021-08-19 21:49:37 +08:00
Ming Deng
fad897346f
Merge pull request #4325 from flycash/revert1
Revert "Merge pull request #4254 from astaxie/develop-2.0"
2020-11-26 20:18:35 +08:00
Ming Deng
650fde66aa Revert "Merge pull request #4254 from astaxie/develop-2.0"
This reverts commit e284b0ddae072311617a6fdd8393eb04aba873d2, reversing
changes made to 8ef8fd26068a7b70865acbabee89f6691ae553a9.
2020-11-26 17:48:29 +08:00
Ming Deng
e284b0ddae
Merge pull request #4254 from astaxie/develop-2.0
Prepare Release v2.0.0-beta
2020-11-07 21:20:18 +08:00
Ming Deng
20a0de6bd0
Merge pull request #4290 from flycash/develop-2.0
fix init error of global instance
2020-11-05 23:51:52 +08:00
Ming Deng
b4396c97bb fix init error of global instance 2020-11-05 22:00:43 +08:00
Ming Deng
471ebba64d
Merge pull request #4281 from flycash/httplibTest
Add test for httplib
2020-10-27 22:08:35 +08:00
Ming Deng
d07a1eaa8e Add test for httplib 2020-10-27 21:58:39 +08:00
Ming Deng
9524036aab
Merge pull request #4278 from flycash/defaultCfg
Add global instance for config module
2020-10-24 22:27:12 +08:00
Ming Deng
45260e4119 Add global instance for config module 2020-10-24 22:13:15 +08:00
Ming Deng
02234dc503
Merge pull request #4277 from flycash/session
support using json string to init session
2020-10-22 09:53:55 +08:00
Ming Deng
05f4e0c146 support using json string to init session 2020-10-21 22:24:53 +08:00
Ming Deng
ae108ec826
Merge pull request #4276 from flycash/newHttpServer
Change NewHttpServer API
2020-10-21 21:59:45 +08:00
Ming Deng
7c61eb058f Change NewHttpServer API 2020-10-21 20:54:33 +08:00
Ming Deng
03ba495b7f
Merge pull request #4275 from flycash/fix-4224
add MaxUploadFile to provide more safety uploading controll
2020-10-21 10:04:32 +08:00
Ming Deng
d26683799a add MaxUploadFile to provide more safety uploading controll 2020-10-20 23:36:34 +08:00
Ming Deng
f9075e8274
Merge pull request #4272 from jianzhiyao/fix-4224
fix 4224:form entity too large casue run out of memory
2020-10-20 20:53:19 +08:00
Ming Deng
022ad862ac
Merge pull request #4274 from flycash/loadCfg
Fix ini Unmarshall method
2020-10-19 21:51:37 +08:00
Ming Deng
93bdf97068 Fix ini Unmarshall method 2020-10-19 21:04:57 +08:00
Anker Jam
3c48719999 complete condition 2020-10-19 00:22:55 +08:00
Anker Jam
cbb3de741d fix application/x-www-form-urlencoded request body oversize 2020-10-18 23:38:08 +08:00
Anker Jam
c510926cb8 fix 4224:form entity too large casue run out of memory 2020-10-18 23:18:13 +08:00
Ming Deng
140a4b90a3
Merge pull request #4266 from flycash/loadCfg
Using unmarshaler to parse config in web module
2020-10-14 22:26:12 +08:00
Ming Deng
c07acaebbc Support unmarshaler 2020-10-14 22:20:25 +08:00
Ming Deng
105b874477
Merge pull request #4265 from flycash/rft/configCtx
Upgrade toml version
2020-10-14 00:28:30 +08:00
Ming Deng
3fc21ae6ec Upgrade toml version 2020-10-14 00:25:31 +08:00
Ming Deng
ccf873fa8b
Merge pull request #4264 from flycash/rft/configCtx
remove config API's context parameter
2020-10-13 22:52:46 +08:00
Ming Deng
2572094a8d remove config API's context parameter 2020-10-13 22:33:39 +08:00
Ming Deng
568626cd57
Merge pull request #4262 from flycash/ftr/toml
Support toml config
2020-10-12 22:55:55 +08:00
Ming Deng
34d6a733e9 Support toml config 2020-10-11 23:26:48 +08:00
Ming Deng
e44f16c672
Merge pull request #4257 from flycash/fix/adapter
Remove scripts directory & update readme
2020-10-09 08:48:08 +08:00
Ming Deng
d41abdb5e4 Remove scripts directory; update readme 2020-10-08 23:18:10 +08:00
Ming Deng
f1358cf78d
Merge pull request #4255 from flycash/fix/adapter
Reorganize packages
2020-10-08 18:37:42 +08:00
Ming Deng
14c1b76569 remove pkg directory;
remove build directory;
remove githook directory;
2020-10-08 18:29:36 +08:00
Ming Deng
2708916f96
Merge pull request #4252 from flycash/fix/adapter
Reset func call depth & add adapter.sh
2020-10-06 18:33:45 +08:00
Ming Deng
034cb3222e Add adapter script which is used to replace v1 package with v2 adapter package 2020-10-06 16:43:16 +08:00
Ming Deng
66804324f2 Fix: Set func call depth as 3 2020-10-06 11:52:24 +08:00
Ming Deng
dc65055cf6
Merge pull request #4250 from flycash/adt/logs
logs Adapter
2020-10-05 23:26:55 +08:00
Ming Deng
8cc74652a2 Fix: adapter's controller must implement ControllerInterface 2020-10-05 23:00:20 +08:00
Ming Deng
6aa6c55f07 logs Adapter 2020-10-05 21:55:26 +08:00
Ming Deng
ff762b561c
Merge pull request #4249 from flycash/rft/moveSession
move core/session to web/session
2020-10-05 19:45:38 +08:00
Ming Deng
d8e8f41230 move core/session to web/session 2020-10-05 19:04:57 +08:00
Ming Deng
9e6b8fcf34
Merge pull request #4248 from flycash/rft/renameInfra
rename infrastructure to core
2020-10-05 18:40:20 +08:00
Ming Deng
48e98482f7 rename infrastructure to core 2020-10-05 18:14:01 +08:00
Ming Deng
ff7a8b966b
Merge pull request #4247 from flycash/adt/cache
Adapter: cache API
2020-10-05 14:46:13 +08:00
Ming Deng
f9bef68aa9 Adapter: cache API 2020-10-05 14:35:12 +08:00
Ming Deng
484beb8bad
Merge pull request #4245 from flycash/ftr/cache-ctx
Add context to cache API
2020-10-05 14:25:09 +08:00
Ming Deng
43560dede4
Merge pull request #4246 from jianzhiyao/frt/seperate_orm_alone
seperate orm alone & deadlock in task module
2020-10-05 14:24:51 +08:00
Anker Jam
c435d231ab complete check 2020-10-05 10:38:14 +08:00
Anker Jam
b838683731 add api for testing 2020-10-05 10:33:23 +08:00
Anker Jam
70cca5e298 make code testable in task module 2020-10-05 10:13:29 +08:00
Anker Jam
f1cca45d8d fix deadlock about changed sign 2020-10-05 01:31:27 +08:00
Anker Jam
4dc694411f fix deadlock in task module 2020-10-05 00:16:58 +08:00
Ming Deng
3364c609de Add context to cache API 2020-10-04 23:12:29 +08:00
Anker Jam
c5d43e87fe seperate orm alone 2020-10-04 22:16:19 +08:00
Ming Deng
b89d9511ab
Merge pull request #4237 from flycash/rft/cache-decup
Decouple web module from cache module
2020-10-04 19:01:31 +08:00
Ming Deng
325a0821c1
Merge pull request #4239 from flycash/rft/httplib
decouple httplib module from web module and config module
2020-09-29 22:22:27 +08:00
Ming Deng
dd3f1ce9be decouple httplib from config 2020-09-27 00:44:02 +08:00
Ming Deng
463e96447a decouple httplib from web module 2020-09-27 00:37:46 +08:00
Ming Deng
03498529b9 Decouple web module from cache module 2020-09-22 22:58:58 +08:00
Ming Deng
9a7c43c404
Merge pull request #4235 from flycash/ftr/adminCommand
decouple web module and task module
2020-09-21 22:50:08 +08:00
Ming Deng
44127edefc design Command for governor module & decouple web module from task module 2020-09-20 14:52:29 +00:00
Ming Deng
089006525e
Merge pull request #4234 from flycash/ftr/multi-sever
Multi server support
2020-09-20 22:44:32 +08:00
Ming Deng
2846043f2a Fix UT 2020-09-20 14:27:30 +00:00
Ming Deng
e6a257f987 Fix BUG 2020-09-20 12:02:28 +00:00
Ming Deng
2473e69417 Rewrite admin service by using multiple server feature 2020-09-20 15:36:53 +08:00
Ming Deng
d455805a0a Multiple server refactor 2020-09-20 15:36:53 +08:00
Ming Deng
bd1cfefec7 rft: Move build info to pkg 2020-09-20 15:36:53 +08:00
Ming Deng
7effdb0e7d
Merge pull request #4233 from flycash/esIndexName
Add IndexNaming interface
2020-09-20 14:22:32 +08:00
Ming Deng
b027968c0b
Merge pull request #4231 from flycash/ut/log
Add tests for log module
2020-09-20 13:50:22 +08:00
Ming Deng
961f300c14 Fix JL tests 2020-09-20 13:15:48 +08:00
Ming Deng
7570abd310
Merge pull request #4232 from flycash/stale-workflows
Add stale.yml
2020-09-19 23:57:40 +08:00
Ming Deng
7c8136710c Add stale.yml 2020-09-19 23:54:33 +08:00
Ming Deng
a3ece98cec Add IndexNaming interface so users can custom the index name when they use es as the logger 2020-09-19 23:49:52 +08:00
Ming Deng
a31dce6216
Merge pull request #4230 from jianzhiyao/frt/movement_for_4198
movement for 4198
2020-09-19 23:24:57 +08:00
Ming Deng
a1782cc22d Add tests for log module 2020-09-19 23:14:17 +08:00
Anker Jam
67f64afa85 movement for 4198 2020-09-19 21:45:37 +08:00
Ming Deng
2539fe3831
Merge pull request #4229 from wangle201210/develop-2.0
Provides a quick format method by PatternLogFormatter struct
2020-09-19 21:25:12 +08:00
wangle
05c125ec2d change to pointer receiver 2020-09-19 20:18:09 +08:00
wangle
6e638ef6c8 Provides a quick format method by PatternLogFormatter struct 2020-09-19 18:28:53 +08:00
Ming Deng
df043f22fc
Merge pull request #4225 from HITWHTigerLiu/develop-2.0
Empty field in validator.Error when label struct tag is not declared #4222
2020-09-17 21:27:18 +08:00
Ming Deng
fbaf3380c6
Merge pull request #4203 from jianzhiyao/frt/proposal_4105
warpping for global modelCache
2020-09-17 21:11:33 +08:00
jianzhiyao
b7bc57c4d1 delete interface 2020-09-16 19:46:14 +08:00
Ming Deng
32cdda96bd
Merge pull request #4205 from AllenX2018/postgres-query-builder
PostgresQueryBuilder
2020-09-14 21:21:59 +08:00
jianzhiyao
5995b00fa2 Merge branch 'develop-2.0' into frt/proposal_4105 2020-09-14 19:16:09 +08:00
l00427301
5618df8c76 Empty field in validator.Error when label struct tag is not declared #4222 2020-09-14 16:18:24 +08:00
AllenX2018
c6c9ad46f9 PostgresQueryBuilder 2020-09-14 09:50:28 +08:00
Ming Deng
5973ef107c
Merge pull request #4221 from flycash/ftr/log_format
fix 4219
2020-09-12 00:02:51 +08:00
Ming Deng
b575fa1ebe fix 4219 2020-09-11 23:48:45 +08:00
Ming Deng
6bbca96c6c
Merge pull request #4220 from flycash/ftr/log_format
refactor log module
2020-09-11 22:08:05 +08:00
Ming Deng
63cd8e4e15 refactor log module 2020-09-11 21:47:22 +08:00
Ming Deng
93736a8e66
Merge pull request #4216 from flycash/ftr/log_format
Log format support
2020-09-11 00:11:27 +08:00
Ming Deng
654d87b210 Merge log_format 2020-09-10 23:31:49 +08:00
Ming Deng
0048b7d158
Merge pull request #4188 from IamCathal/custom-log-formatter-third-pr
Custom logging format PR#3
2020-09-10 22:40:48 +08:00
jianzhiyao
00e44952ff optimize modelCache 2020-09-09 19:04:34 +08:00
IamCathal
8982f5d702 Add unit tests for custom log formatter
Also moved is Colorful check to WriteMsg function to make the interface for user's using the custom logging formatting simpler. The user does not have to check if the text is colorful now, the WriteMsg function handles it.
2020-09-09 00:23:57 +01:00
Ming Deng
6612bc4c2a
Merge pull request #4214 from flycash/rft/dbOption
Optimize orm by using BDOption rather than hints
2020-09-09 00:06:44 +08:00
Ming Deng
f580a714d5 Optimize orm by using BDOption rather than hints 2020-09-08 21:44:14 +08:00
Ming Deng
9ccd58bfff
Merge pull request #4211 from flycash/adt/all
allow users to ignore some table when run orm commands
2020-09-07 21:52:39 +08:00
Ming Deng
0f50b07a20 allow users to ignore some table when run orm commands 2020-09-07 21:40:44 +08:00
Ming Deng
b86cf22fc4
Merge pull request #4210 from flycash/adt/all
Move pr 3784
2020-09-07 20:53:45 +08:00
Ming Deng
6bf01eaeca Move pr 3784 here 2020-09-07 20:37:05 +08:00
Ming Deng
8e015deee5
Merge pull request #4208 from flycash/adt/all
Adapter: all module
2020-09-06 19:58:46 +08:00
Ming Deng
3acda41bc7 Fix UT 2020-09-06 10:39:20 +00:00
Ming Deng
5b3dd7e50f Adapter: orm 2020-09-06 13:33:52 +08:00
Ming Deng
f4a43814be Adapter: utils 2020-09-05 18:07:42 +08:00
Ming Deng
35f1bd2119 Adapter: testing 2020-09-05 16:58:49 +08:00
Ming Deng
f6c95ad534 Adapter: swagger module 2020-09-05 16:56:56 +08:00
Ming Deng
f1950482c2 Adapter: plugin 2020-09-05 16:54:22 +08:00
Ming Deng
1dae2c9eb3 Adapter: web module 2020-09-05 16:24:19 +08:00
Ming Deng
8ef9965eef Adapter: session module 2020-09-03 23:37:07 +08:00
Ming Deng
3530457ff9 Adapter: toolbox module 2020-09-03 21:34:57 +08:00
Ming Deng
cbd51616f1 adapter: validation module 2020-09-02 23:23:48 +08:00
Ming Deng
bdd8df6751 adapt migration 2020-09-02 21:01:54 +08:00
Ming Deng
8fc4f8847c adapt grace and metric 2020-09-02 20:43:35 +08:00
Ming Deng
3bf5cde38c adapt context 2020-09-02 20:36:53 +08:00
Anker Jam
7a53baaf9b rename modelRegister to modelCacheHandler 2020-09-02 00:33:46 +08:00
Anker Jam
7574b91760 add type modelRegister interface into Ormer 2020-09-02 00:26:25 +08:00
Ming Deng
78d91062c9 Adapt new API to old API: httplib 2020-09-01 22:16:49 +08:00
Ming Deng
23792401b5
Merge pull request #4201 from jianzhiyao/frt/proposal_4105
WIP:supports for proposal 4105
2020-09-01 22:05:15 +08:00
Anker Jam
e54dbabf0b movement for global modelCache 2020-09-01 21:56:48 +08:00
Ming Deng
cdc8110ea4
Merge pull request #4202 from flycash/adt/config
Using new API to adapt to old API
2020-09-01 21:50:08 +08:00
Ming Deng
185d55eb46 adapt config 2020-09-01 21:29:26 +08:00
Ming Deng
8e879726fe
Merge pull request #4200 from flycash/ftr/config-sub
Implement Sub, Unmarshaler and OnChange methods for yaml, json, xml
2020-08-31 22:29:14 +08:00
Ming Deng
33b052bc7a support json 2020-08-31 14:15:01 +00:00
Ming Deng
087399c44a support xml 2020-08-31 13:57:26 +00:00
Ming Deng
f4f200cf04 enhance yaml 2020-08-31 13:02:38 +00:00
Ming Deng
0a58428220
Merge pull request #4199 from flycash/rft/task-api
Add ctx to Task module API
2020-08-31 19:43:53 +08:00
Ming Deng
c0462f75bf Add ctx to Task module API 2020-08-30 16:18:59 +00:00
Ming Deng
5cf33f2655
Merge pull request #4197 from flycash/rft/session-api
Add ctx to session API
2020-08-31 00:14:52 +08:00
Ming Deng
670064686e Add ctx to session API 2020-08-30 15:39:07 +00:00
Ming Deng
0019e0fc1b
Merge pull request #4195 from flycash/ftr/etcd
Add contect as first parameter for all config method
2020-08-30 00:42:15 +08:00
Ming Deng
03bec05714 Add contect as first parameter for all config method 2020-08-29 16:25:20 +00:00
Ming Deng
e831b97eb8
Merge pull request #4194 from flycash/ftr/etcd
Support etcd
2020-08-29 22:44:55 +08:00
Ming Deng
81b9a1382a Fix UT 2020-08-29 14:27:06 +00:00
IamCathal
0189e6329a Add global logging override 2020-08-28 18:47:28 +01:00
IamCathal
6684924e99 empty commit to restart CI again 2020-08-28 18:30:41 +01:00
IamCathal
e0a934af1d empty commit to restart CI 2020-08-28 18:24:57 +01:00
IamCathal
8178f035a0 Custom formatting opts implementation 2020-08-28 18:18:28 +01:00
IamCathal
2b39ff7837 New opts formatter working for console 2020-08-28 18:00:45 +01:00
Ming Deng
c2361170b3 Support etcd 2020-08-29 00:07:33 +08:00
Ming Deng
5b35bf6065
Merge pull request #4192 from AllenX2018/supplement-datetimePrecision-UT
supplement datetime precision UT
2020-08-26 19:52:19 +08:00
Ming Deng
14c911e9d7
Merge pull request #4190 from flycash/ftr/time-precision
Support precision
2020-08-26 12:45:17 +08:00
Ming Deng
9472cba6c9 Fix UT 2020-08-26 04:16:09 +00:00
AllenX2018
b83094ac1e supplement datetime precision UT 2020-08-26 11:51:05 +08:00
Ming Deng
1cb0ff560d Support precision 2020-08-25 13:07:21 +00:00
Ming Deng
cceecad8c2
Merge pull request #4186 from AllenX2018/Feature-datetime-precision
Feature: implement the time precison for time.Time type
2020-08-25 21:05:08 +08:00
IamCathal
d24f861629 empty commit to restart CI 2020-08-24 21:00:58 +01:00
IamCathal
c2471b22ad Remove ineffectual assignments
Removed 3 lines due to warning from test suite saying these lines had innefectual assignments
2020-08-24 20:54:55 +01:00
IamCathal
c5970766a3 Add init to es.go 2020-08-24 20:41:39 +01:00
IamCathal
48a98ec1a5 Fix init for alils.go 2020-08-24 20:39:53 +01:00
IamCathal
ed1d2c7f6e Add custom logging format functionality and global formatter functionality 2020-08-24 20:22:38 +01:00
AllenX2018
7a94996e22 Feature: implement the time precison for time.Time type 2020-08-24 20:23:54 +08:00
Ming Deng
597c55d547
Merge pull request #4183 from flycash/rft/module-2
Reorganize package
2020-08-23 21:43:48 +08:00
Ming Deng
026e8bc55a Merge branch 'develop-2.0' of https://github.com/astaxie/beego into rft/module-2 2020-08-23 21:25:15 +08:00
Ming Deng
581e48679e Merge pull request #4173 from AllenX2018/fix-bug-queryRow
Fix issue 3866
2020-08-23 21:04:34 +08:00
Ming Deng
09afe0ae8e
Merge pull request #4179 from IamCathal/custom-log-formatter-secondpr
Custom log formatter secondpr
2020-08-22 21:36:50 +08:00
IamCathal
08e49ca323 Test empty commit 2020-08-20 19:32:42 +01:00
IamCathal
e1da804b2b Add format func to alils 2020-08-20 19:20:30 +01:00
IamCathal
705e091593 Add format call before logging 2020-08-20 19:06:51 +01:00
IamCathal
6bdedff457 LogFormatter Implementation 2020-08-20 19:00:35 +01:00
Ming Deng
f3be6dd2e9
Merge pull request #4173 from AllenX2018/fix-bug-queryRow
Fix issue 3866
2020-08-20 22:25:37 +08:00
AllenX2018
9fe353dd0b Fix issue 3886 2020-08-20 10:00:49 +08:00
Ming Deng
9003ca3eef
Merge pull request #4174 from IamCathal/custom-log-formatter-firstpr
Custom Log Formatter PR#1
2020-08-19 23:37:44 +08:00
IamCathal
ff5ac3adf4 Update signature of WriteMsg in es.go 2020-08-19 16:20:19 +01:00
IamCathal
ca4a217783 Merge branch 'develop-2.0' into custom-log-formatter-firstpr 2020-08-19 16:05:42 +01:00
Ming Deng
e6ea307549
Merge pull request #4175 from flycash/ftr/config
Add more methods to Configer
2020-08-19 22:44:43 +08:00
Ming Deng
2c16c7b917 Add more methods to Configer 2020-08-19 22:09:05 +08:00
IamCathal
77ddc3338f Fix file path logging for enableFullFilePath 2020-08-19 15:07:46 +01:00
IamCathal
ac3a549187 Fix test with new parameters 2020-08-19 14:21:29 +01:00
IamCathal
fe56de06b5 Add enableFullFilePath field to BeeLogger 2020-08-18 21:30:39 +01:00
IamCathal
6c002a3124 Update WriteMsg signatures for custom log formatting update 2020-08-18 21:30:11 +01:00
Ming Deng
cead72c6df
Merge pull request #4170 from flycash/rft/ormFilter
Refactor orm filter
2020-08-18 22:46:45 +08:00
Ming Deng
7fe4eaef50 Refactor orm filter 2020-08-18 14:31:06 +00:00
Ming Deng
63599c0032
Merge pull request #4168 from flycash/ftr/layout
Add git hooks
2020-08-18 21:08:56 +08:00
Ming Deng
4db256c9fb Add git hooks 2020-08-18 20:56:15 +08:00
Ming Deng
c548764c8e
Merge pull request #4163 from flycash/ftr/rmFiles
Remove files
2020-08-16 23:17:05 +08:00
Ming Deng
b4a85c8f13 Remove files 2020-08-16 23:09:19 +08:00
Ming Deng
94f476fa39
Merge pull request #4158 from jianzhiyao/frt/fix_spk_upsert
fix:return error when calling ``InsertOrUpdate`` is successful with string primary key
2020-08-16 21:21:25 +08:00
Ming Deng
8574e30b3a
Merge pull request #4160 from AllenX2018/Improve-orm.Fielder-function
fix issue #3776
2020-08-14 22:20:07 +08:00
AllenX2018
7442919f5a fix issue #3776 2020-08-14 17:11:52 +08:00
Ming Deng
f6ec4efc70
Merge pull request #4156 from flycash/ftr/bean
Supporting default value by using filter
2020-08-14 15:47:50 +08:00
jianzhiyao
7b899aa9af add ErrLastInsertIdUnavailable 2020-08-14 15:09:47 +08:00
Ming Deng
f73eee75ff Merge develop-2.0 2020-08-14 14:34:59 +08:00
jianzhiyao
739b8bab0c fix UT 2020-08-14 10:31:08 +08:00
jianzhiyao
139c393f08 add const ErrLastInsertIdUnavailable 2020-08-14 09:59:11 +08:00
Ming Deng
bdec93986b Bean: Support autowire by tag
Orm: Support default value filter
2020-08-13 21:26:39 +08:00
jianzhiyao
7ce0fde171 fix:return error when calling `InsertOrUpdate` is successful with string primary key 2020-08-13 19:14:00 +08:00
Ming Deng
d6a2621b3c
Merge pull request #4137 from phiphi282/change_redis_provider
Add additional options to redis session prov
2020-08-12 13:38:44 +08:00
Phillip Stagnet
813a4df3c5
Make sure expiry time is in seconds 2020-08-11 16:21:43 +02:00
Phillip Stagnet
7267f5e573
Add new config option into provider struct 2020-08-11 16:09:29 +02:00
Ming Deng
5bc8d90d7f
Merge pull request #4150 from jianzhiyao/frt/fix_3830
fix:return error after inserting data when primary key is string
2020-08-11 21:22:17 +08:00
jianzhiyao
2d1c02e1c1 Merge branch 'develop-2.0' of https://github.com/astaxie/beego into frt/fix_3830
# Conflicts:
#	pkg/orm/orm_test.go
2020-08-11 17:37:24 +08:00
jianzhiyao
9ca9535c48 fix:return error after inserting data when primary key is string 2020-08-11 16:53:31 +08:00
Phillip Stagnet
d1d9df74c7
Merge branch 'develop-2.0' of github.com:astaxie/beego into change_redis_provider 2020-08-11 10:47:06 +02:00
Ming Deng
d326d74c34
Merge pull request #4148 from flycash/fix/end2end
Fix prometheus and opentracing bug found in end2end tests
2020-08-11 16:33:54 +08:00
Ming Deng
82178a487b Merge develop-2.0 and resolve conflict 2020-08-11 08:16:04 +00:00
Ming Deng
a1b7fd3c93
Merge pull request #4147 from jianzhiyao/frt/specify_index_2
specify index
2020-08-11 16:13:13 +08:00
Phillip Stagnet
0813471202
Merge branch 'develop-2.0' of github.com:astaxie/beego into change_redis_provider 2020-08-11 09:52:53 +02:00
jianzhiyao
ce698aacf6 rm some methods 2020-08-11 12:06:02 +08:00
Ming Deng
c22af4c611 Fix Tracing and prometheus bug 2020-08-11 03:23:38 +00:00
Anker Jam
f8c0e6fec5 fix UT 2020-08-11 00:06:36 +08:00
Anker Jam
882f1273c8 add UT for specifying indexes 2020-08-10 23:27:03 +08:00
jianzhiyao
5a1fa4e1ec specify index 2020-08-10 18:46:16 +08:00
Ming Deng
d05460237c
Merge pull request #4145 from flycash/ftr/ormTracing
Support prometheus and opentracing for ORM and httplib module
2020-08-10 13:53:23 +08:00
Ming Deng
75107f735e Support opentracing filter 2020-08-09 14:59:41 +00:00
Ming Deng
2e891152dd deprecated httplib and then support prometheus for httplib 2020-08-09 14:59:41 +00:00
Ming Deng
dec98f004c Support opentracing filter for Orm 2020-08-09 14:59:41 +00:00
Ming Deng
26b016a3a4
Merge pull request #4143 from flycash/fix/moveIni
Move init so it will be default implementation of config
2020-08-09 22:51:47 +08:00
Ming Deng
19aae0b7e1
Merge pull request #4107 from AllenX2018/fix-comment-router-issue
add comment router path configuration
2020-08-09 19:23:05 +08:00
Ming Deng
2e192e1ed0 Depracated config module and recommend using pkg/config 2020-08-08 13:26:30 +00:00
Ming Deng
f9a3eae9d5 Move init so it will be default implementation of config 2020-08-08 13:17:49 +00:00
Ming Deng
7fc1e4de96
Merge pull request #4141 from flycash/ftr/ormInterceptor
Orm filter support
2020-08-08 20:52:37 +08:00
AllenX2018
993ccac2bd fix comment router generate issue 2020-08-08 16:17:12 +08:00
Ming Deng
2fd65a469c Support prometheus 2020-08-07 14:14:07 +00:00
Ming Deng
a2fa073072
Merge pull request #4139 from IamCathal/coc-grammar-fixes
More minor grammar fixes
2020-08-07 22:00:22 +08:00
Ming Deng
08cec9178f Orm filter support 2020-08-07 13:45:24 +00:00
IamCathal
63b3fc4a99 Fix retry amount comment 2020-08-06 16:09:06 +01:00
IamCathal
1b4bb43df0 More minor grammar fixes 2020-08-06 16:07:18 +01:00
Phillip Stagnet
ec55edfbc4
Add additional options to redis session prov
Adding option for frequency of checking timed out connections as well as
an option to specify retries.

These changes make redis provider more stable since connection problems
are becoming fewer.

Since redigo does not have this options and since redis_sentinel and
redis_cluster are using go-redis as a client, this commit changes from
redigo to go-redis for redis session provider.

Added tests for redis session provider as well.
2020-08-06 11:14:36 +02:00
Ming Deng
2fce8f9d1b
Merge pull request #4124 from phiphi282/session_exists_return_err
Update session provider interface to return errors on SessionExist
2020-08-06 09:17:49 +08:00
Ming Deng
15489fa76a
Merge pull request #4135 from IamCathal/grammar-fixes
Minor grammar fixes
2020-08-06 09:05:30 +08:00
IamCathal
e7d8bab5d9 Improved definition of DefaultEvery 2020-08-05 17:56:11 +01:00
IamCathal
2f5683610f Minor grammar fixes 2020-08-05 17:50:05 +01:00
Phillip Stagnet
5c8c088684
Revert "Change interface in session README"
This reverts commit 6f5c5bd3a65561db56aca26eae4a50abef8fa5b4.
2020-08-05 18:33:17 +02:00
Phillip Stagnet
009074725e
Move interface change to pkg/session/README.md 2020-08-05 18:32:33 +02:00
Phillip Stagnet
ce50ca22d7
Merge branch 'develop-2.0' of github.com:astaxie/beego into session_exists_return_err 2020-08-05 18:30:19 +02:00
Phillip Stagnet
3052c64b6c
Revert "Add error to SessionExist interface"
This reverts commit 28e6b3b92450b0ca0e9c1342d400f8810e4d5e5a.
2020-08-05 18:29:47 +02:00
Phillip Stagnet
5f2f6e4f86
Add interface change in pkg folder 2020-08-05 18:29:22 +02:00
Ming Deng
3382a5baa1
Merge pull request #4134 from flycash/ftr/ormInterceptor
Deprecated old web module
2020-08-05 22:22:59 +08:00
Ming Deng
882aa9b967 Deprecated old web module 2020-08-05 21:57:20 +08:00
Ming Deng
02972d8702
Merge pull request #4130 from flycash/ftr/prometheuseAndOpentracing
Support prometheus and opentracing by using FilterChainFunc
2020-08-05 15:46:03 +08:00
Ming Deng
261b704d8b Fix UT 2020-08-05 07:25:34 +00:00
Ming Deng
6c6cf91741 Support prometheus and opentracing filter 2020-08-04 23:15:42 +08:00
Ming Deng
ae8461f95d
Merge pull request #4125 from flycash/ftr/middleware
Support FilterChain
2020-08-04 23:06:18 +08:00
Ming Deng
aa3987f816 Merge remote-tracking branch 'origin/develop' into ftr/middleware 2020-08-04 22:26:01 +08:00
Ming Deng
3dc5ec1060
Merge pull request #4129 from astaxie/revert-4128-fix-ci-fail
Revert "fix CI fail for connection log test"
2020-08-04 21:38:50 +08:00
Ming Deng
1961c1e441
Revert "fix CI fail for connection log test" 2020-08-04 21:37:46 +08:00
Ming Deng
787bb60b42
Merge pull request #4128 from AllenX2018/fix-ci-fail
fix CI fail for connection log test
2020-08-04 21:14:45 +08:00
AllenX2018
12b984861d fix CI fail for connection log test 2020-08-04 20:32:07 +08:00
Ming Deng
79ffef90e3 support filter chain 2020-08-04 07:26:51 +00:00
Ming Deng
310161f9d4
Merge pull request #4126 from flycash/fix/secureFlagV1
XSRF add secure and http only flag
2020-08-03 21:24:23 +08:00
Ming Deng
a0d1c42dac XSRF add secure and http only flag 2020-08-03 21:04:33 +08:00
Phillip Stagnet
6f5c5bd3a6
Change interface in session README 2020-08-03 13:33:30 +02:00
Phillip Stagnet
28e6b3b924
Add error to SessionExist interface
Implement changed interface for all default providers as well and change
tests accordingly
2020-08-03 13:31:49 +02:00
Ming Deng
9e1346ef4d
Merge pull request #4113 from flycash/ftr/usingPkg
using pkg module
2020-07-31 13:40:39 +08:00
Ming Deng
9f295067b7 Resolve conflict 2020-07-30 22:44:44 +08:00
Ming Deng
71776e4bef
Merge pull request #4114 from wangle201210/develop-2.0
Add the operator(>,>=,<,<=,=,!=) of orm
2020-07-30 16:51:02 +08:00
Ming Deng
87b40ee9e7
Merge pull request #4116 from livelyRyan/patch-2
添加 BConfig.Listen.ClientAuth 字段及处理逻辑
2020-07-30 16:07:00 +08:00
Mr. Myy
7831638f37
移除多余的条件判断 2020-07-30 14:48:46 +08:00
Mr. Myy
5203804165
调整默认配置中的 ClientAuth 值,使之与原来的行为保持一致 2020-07-30 14:46:17 +08:00
Ming Deng
d4074b5004
Merge pull request #4103 from flycash/ftr/newOrmWithDB
Enhance: NewOrmUsingDB & remove useless methods
2020-07-30 11:43:47 +08:00
Mr. Myy
0815e77f9a
修复笔误产生的拼写错误 2020-07-30 11:20:22 +08:00
Mr. Myy
c46ba86215
修复笔误产生的拼写错误 2020-07-30 11:18:14 +08:00
Mr. Myy
9d23e5a3fb
简化代码写法 2020-07-30 11:03:32 +08:00
Mr. Myy
513a4afff1
对 Listen 结构体增加 ClientAuth 字段
对 Listen 结构体增加 ClientAuth 字段,赋予默认配置对象该字段值为 tls.VerifyClientCertIfGiven,与原代码逻辑的默认值保持一致
2020-07-30 10:59:32 +08:00
Mr. Myy
15e11931fc
添加对 BConfig.Listen.ClientAuth 字段的逻辑处理。当指定了该配置时,使用配置的值来作为验证客户端的方式。如果没指定,使用默认值 tls.RequireAndVerifyClientCert 2020-07-30 10:53:30 +08:00
Ming Deng
7d561607d8
Merge pull request #4111 from liuhaogui/develop
添加配置文件路径环境变量
2020-07-30 09:14:12 +08:00
wangle
22b8cae73b Add the operator(>,>=,<,<=,=,!=) of orm
eg:
qs.Filter("counts__>=","20")
qs.Filter("counts__!=","20")
2020-07-29 23:23:02 +08:00
Ming Deng
aa06a10493 uing pkg module 2020-07-29 14:42:27 +00:00
Ming Deng
9b58c2836c Merge develop-2.0 and resolve confilct 2020-07-29 22:26:29 +08:00
刘豪贵
15f04b8da4 add env BEEGO_CONFIG_PATH 2020-07-29 21:57:16 +08:00
Ming Deng
7312197732
Merge pull request #4098 from jianzhiyao/frt/stmt_config
make stmt cache size configurable & wrap kv
2020-07-29 20:57:07 +08:00
jianzhiyao
e87de70c6d adapt wrapping kv 2020-07-29 00:45:41 +08:00
jianzhiyao
4304b40a82 Merge branch 'frt/wrap_kv' into frt/stmt_config
# Conflicts:
#	pkg/orm/constant.go
#	pkg/orm/db_alias.go
2020-07-28 18:32:24 +08:00
jianzhiyao
e8facd28f5 wrap kv 2020-07-28 17:37:36 +08:00
Ming Deng
54ef476600 add tag interfaces and remove log.go 2020-07-28 06:28:51 +00:00
jianzhiyao
756df9385f make stmt cache size configurable 2020-07-28 12:57:19 +08:00
Ming Deng
21f281655d remove QueryRelated and QueryRelatedCtx 2020-07-27 21:22:40 +08:00
Ming Deng
2e7fb81348 deprecated orm.go and add NewOrmUsingDB method 2020-07-27 21:19:34 +08:00
Ming Deng
ebc0207909
Merge pull request #4096 from jianzhiyao/request_context
fix memory leak of request context
2020-07-27 18:04:37 +08:00
jianzhiyao
2386c9c80d delete useless if-stmt 2020-07-26 22:37:42 +08:00
Ming Deng
b9f9fcca5f
Merge pull request #4099 from jianzhiyao/fix_3869
orm.rawPrepare support FlatParams
2020-07-26 21:01:39 +08:00
jianzhiyao
16d71893cd orm.rawPrepare support FlatParams 2020-07-26 19:40:13 +08:00
jianzhiyao
cfff0f3b46 fix memory leak of request context 2020-07-25 00:00:34 +08:00
Ming Deng
93eb7c6b83
Merge pull request #4091 from flycash/ftr/moveToPkg
Ftr: move to pkg
2020-07-23 09:36:29 +08:00
Ming Deng
79c2157ad4 Fix UT 2020-07-22 15:46:29 +00:00
Ming Deng
30eb889a91 Format code 2020-07-22 23:00:06 +08:00
Ming Deng
9c51952db4 Move package 2020-07-22 22:55:59 +08:00
Ming Deng
16b66509f6
Merge pull request #4083 from IamCathal/content-length
Add Content-length field for logging
2020-07-21 15:47:58 +08:00
Ming Deng
d5695060c5
Merge pull request #4082 from flycash/ftr/newOrm
Refactor RegisterDatabase
2020-07-21 15:47:40 +08:00
Ming Deng
af2143f8fb
Merge pull request #4084 from astaxie/develop
Align develop-2.0
2020-07-21 09:36:54 +08:00
IamCathal
a66b9950e7 Add Content-length field for logging 2020-07-20 21:23:21 +01:00
Ming Deng
44460bc457 Refactor RegisterDatabase 2020-07-20 15:52:40 +00:00
Ming Deng
41feb3a711
Merge pull request #4078 from jianzhiyao/frt/orm_merge
refactor orm
2020-07-20 23:50:40 +08:00
jianzhiyao
b6f7d30f9f fix unit test 2020-07-20 19:10:57 +08:00
jianzhiyao
4aad313de7 do not judge tx status in txOrm 2020-07-20 17:34:58 +08:00
jianzhiyao
aefe21b63a complete error log 2020-07-20 17:25:27 +08:00
jianzhiyao
32da446eb1 refactor orm 2020-07-19 23:46:42 +08:00
Ming Deng
d9c016ed98
Merge pull request #4076 from flycash/ftr/taskLog
Store nearest error info
2020-07-19 23:23:13 +08:00
Ming Deng
7258ef113a Store nearest error info 2020-07-19 14:34:57 +00:00
Ming Deng
d6779c4a90
Merge pull request #4075 from flycash/fix/stable-ut
Fix orm test when using Driver = mysql
2020-07-19 21:22:36 +08:00
Ming Deng
192a278a2a Fix orm test when using Driver = mysql 2020-07-19 12:56:58 +00:00
Ming Deng
7a48fbb698
Merge pull request #4066 from playHing/self-dev
Fix concurrent issue of context/input Query method
2020-07-16 13:52:11 +08:00
playHing
3e2c795410 Rlock for form query 2020-07-15 20:44:59 +08:00
playHing
55e6298f29 Fix concurrent form parsing and getting 2020-07-15 20:44:59 +08:00
playHing
b50fb44950 Add bench test on context input query 2020-07-15 20:44:59 +08:00
Ming Deng
9d936c58bf
Merge pull request #4070 from flycash/develop-2.0
Move orm to pkg/orm
2020-07-15 10:50:05 +08:00
Ming Deng
ffe1d52120 Move orm to pkg/orm 2020-07-15 10:05:11 +08:00
Ming Deng
1c0714405a
Merge pull request #4068 from jianzhiyao/fix_3898
fix `index out of range` when sid len = 1
2020-07-15 00:03:59 +08:00
jianzhiyao
678b90385b add log 2020-07-14 09:57:13 +08:00
jianzhiyao
5940ae33c2 fix index out of range when sid len = 1
add unit test for sess_file.go
2020-07-13 19:14:53 +08:00
Ming Deng
3db31385cf
Merge pull request #4065 from Acmefocus/develop
update README.md
2020-07-11 23:16:36 +08:00
Acmefocus
2b9aaa5b0d update README.md
Signed-off-by: Acmefocus <107723772@qq.com>
2020-07-10 09:58:06 +08:00
Acmefocus
dced745d55 Merge branch 'develop' of https://github.com/Acmefocus/beego into develop 2020-07-09 18:15:25 +08:00
Acmefocus
25ba78ea72 update README.md
Signed-off-by: Acmefocus <107723772@qq.com>
2020-07-09 18:14:31 +08:00
Acmefocus
863b5bd0f4 Merge branch 'develop' of https://github.com/Acmefocus/beego into develop
Signed-off-by: Acmefocus <107723772@qq.com>
2020-07-09 17:59:07 +08:00
Acmefocus
ba3153621a Merge branch 'develop' of https://github.com/Acmefocus/beego into develop 2020-07-09 17:47:46 +08:00
Acmefocus
40cdc877b6 Update README.md
Signed-off-by: Acmefocus <107723772@qq.com>
2020-07-09 17:38:08 +08:00
Acmefocus
76debb1899
Update README.md 2020-07-09 17:18:01 +08:00
Ming Deng
35dcc3df7c
Merge pull request #4058 from a631807682/fix/issues/4054
Fix response payload too large
2020-07-09 16:41:11 +08:00
Chenrui
c3f14a0ad6
refactor: log error when payload too large 2020-07-09 09:45:40 +08:00
Ming Deng
8ee167bc7b
Merge pull request #4051 from gmelodie/sleep-on-reconnect-3972
Add sleep on reconnect
2020-07-09 09:41:04 +08:00
Cathal
2eccb23461 Add sleep on reconnect functionality 2020-07-08 17:30:34 +01:00
Ming Deng
28d3f624a3
Merge pull request #4055 from tayoogunbiyi/develop
Allow Healthcheck endpoint return JSON for Kubernetes
2020-07-08 23:51:03 +08:00
Ming Deng
926b80d1d8
Merge pull request #4061 from flycash/race-condition
Fix 4059
2020-07-08 23:49:54 +08:00
Ming Deng
c08b27111c Fix 4059 2020-07-08 23:32:18 +08:00
Chenrui
03f78b2e4a
fix: add error code support 2020-07-08 18:09:01 +08:00
Chenrui
946a42c021
fix: response http 413 when body size larger then MaxMemory. 2020-07-08 17:14:52 +08:00
Eyitayo Ogunbiyi
d7b0d55357 added extra check for same response lengths 2020-07-07 17:23:52 +01:00
Eyitayo Ogunbiyi
728bf34006 refacted cache health check from toolbox 2020-07-07 16:46:59 +01:00
Eyitayo Ogunbiyi
e0f8c6832d added test for buildingHealthCheckResponse 2020-07-07 16:28:16 +01:00
Eyitayo Ogunbiyi
469dc7bea9 refactored the building of healthcheck response map 2020-07-07 16:09:22 +01:00
Eyitayo Ogunbiyi
ca0c64b69e refactored tests for health check endpoint 2020-07-07 15:21:38 +01:00
Eyitayo Ogunbiyi
5a4a082af0 renamed functions for clarity 2020-07-07 14:54:21 +01:00
Ming Deng
9dc660c1da
Merge pull request #4056 from gmelodie/reconn-bug-3971
Fix reconnection bug in logs/conn.go
2020-07-07 20:25:44 +08:00
Gabriel Cruz
d8724cb122
Add error returning to writeln 2020-07-06 21:38:47 +02:00
Gabriel Cruz
fc56c562db
Fix logger reconnection 2020-07-06 21:38:47 +02:00
Eyitayo Ogunbiyi
8d1a9bc92e added tests for health check endpoints 2020-07-06 19:34:48 +01:00
Eyitayo Ogunbiyi
db547a7c84 added test for execJson 2020-07-06 16:04:29 +01:00
Eyitayo Ogunbiyi
7c575585e9 added conditional json flag when trying to view healthchecks 2020-07-06 15:27:12 +01:00
Ming Deng
289f86247e
Merge pull request #4053 from flycash/ftr/test-docker
Add docker-compose to support running unit test locally
2020-07-05 22:08:20 +08:00
Ming Deng
ca9b21bb30 Add docker-compose to support running test 2020-07-04 13:42:20 +00:00
Ming Deng
8ef8fd2606
Merge pull request #4036 from astaxie/develop
V1.12.2
2020-06-30 23:25:29 +08:00
Ming Deng
d6ef33feee
Merge pull request #4045 from flycash/preprare-1.12.2
Remove tidb dependency
2020-06-30 23:16:41 +08:00
Ming Deng
2f5ed5b433 Remove tidb dependency 2020-06-30 21:04:37 +08:00
Ming Deng
9c18dbe7dc
Merge pull request #4044 from flycash/upgrade_version
upgrade version
2020-06-30 20:58:14 +08:00
Ming Deng
01219944a4 upgrade version 2020-06-30 20:55:31 +08:00
Ming Deng
4fac6ceb3f
Merge pull request #4039 from flycash/fixbug
Fix ES bug
2020-06-30 13:18:13 +08:00
Ming Deng
1c4085e7ea
Update es.go 2020-06-30 10:12:10 +08:00
Ming Deng
2117562113
Update es.go 2020-06-30 10:09:36 +08:00
Ming Deng
1f9da8d75b Fix ES bug 2020-06-29 22:25:22 +08:00
Ming Deng
9dea9f9ae7
Merge pull request #3994 from HarryWang29/develop
update support bit operation
2020-06-29 20:27:36 +08:00
harry890829
0f6735e20d Merge branch 'develop' of https://github.com/astaxie/beego into develop
 Conflicts:
	go.mod
	go.sum
2020-06-29 16:48:03 +08:00
Ming Deng
ad68e8d866
Merge pull request #4033 from jianzhiyao/develop
make redis client idle timeout configurable
2020-06-28 23:14:28 +08:00
Ming Deng
26beef756f
Merge pull request #4038 from flycash/fixbug
Fix ES index problem
2020-06-28 23:14:07 +08:00
jianzhiyao
5c9cc805a1 make redis client idle timeout configurable 2020-06-28 22:20:46 +08:00
Ming Deng
de51bd28d7 Fix ES index problem 2020-06-28 21:12:12 +08:00
Ming Deng
6b6a0e8a56
Merge pull request #4032 from jianzhiyao/develop
fix strings.Repeat panic
2020-06-26 17:51:47 +08:00
Ming Deng
8039cc8e59
Merge pull request #4017 from guhan121/fix#4000
Prohibit multiple calls SetDefaultMessage.
2020-06-26 17:49:36 +08:00
jianzhiyao
b88b7d2899 fix strings.Repeat panic 2020-06-25 23:48:07 +08:00
qiantao
e725192072 fix #4000 2020-06-25 22:11:32 +08:00
Ming Deng
469f2c226d
Merge pull request #3998 from guhan121/go_modules_route_compatibility
for go modules, generate route by `GO111MODULE=on`
2020-06-25 20:30:27 +08:00
Ming Deng
828b20163d
Merge pull request #4029 from flycash/feature/buildInfo
Add build info for prometheus
2020-06-25 18:37:11 +08:00
Ming Deng
9c5eab4834 Add build info for prometheus 2020-06-25 17:44:40 +08:00
Ming Deng
1813d414ae
Merge pull request #4027 from flycash/develop
Move many PR's change here since the original authors are responseless
2020-06-25 02:17:49 +08:00
Ming Deng
6052524a28
Merge pull request #4028 from jianzhiyao/develop
acquire() in Lock
2020-06-23 23:58:42 +08:00
Ming Deng
3ce68d6a30 Move many PR's change here since the original authors are responseless 2020-06-23 23:14:51 +08:00
jianzhiyao
89420eacd0 go destroy 2020-06-23 23:05:58 +08:00
jianzhiyao
6d9862b924 acquire() in Lock 2020-06-23 22:29:41 +08:00
Ming Deng
96658121dc
Merge pull request #3818 from dbt4516/develop
Get the real location of the log directory before using filepath.Walk function when remove old logs
2020-06-23 21:17:14 +08:00
Ming Deng
43a3623f51
Merge pull request #3803 from yinggaozhen/fix-statistics
GetMapData change to read lock
2020-06-23 21:08:32 +08:00
Ming Deng
089dfbdbee
Merge pull request #4016 from huija/develop
Update redis.go
2020-06-23 20:41:42 +08:00
Ming Deng
526a5463d6
Merge pull request #4025 from jianzhiyao/develop
Fix: Too Many Prepare Statement
2020-06-23 20:33:04 +08:00
jianzhiyao
a28d294a83 upgrade acquire method return *sql.Stmt 2020-06-23 13:46:19 +08:00
huija
f70fd5babf add comments on Scan func 2020-06-23 12:32:26 +08:00
qiantao
a764e17fbf check ci 2020-06-23 10:43:51 +08:00
Ming Deng
f5c580a403
Merge pull request #3739 from nuczzz/develop
fix graceful bug: old process didn't exist when graceful restart
2020-06-23 00:10:53 +08:00
Ming Deng
7210dc24b6
Merge pull request #3743 from Colstuwjx/fix/orm-end-printstack
Fix/orm end printstack
2020-06-22 23:59:16 +08:00
Ming Deng
1060dc7df8
Merge pull request #4026 from flycash/develop
fix UT
2020-06-22 23:36:25 +08:00
Ming Deng
3ab1e48217 fix UT 2020-06-22 23:24:15 +08:00
jianzhiyao
a5e8344a0a add stmt garbage recycle 2020-06-22 23:23:52 +08:00
Ming Deng
e1386c448c
Merge pull request #4022 from jianzhiyao/develop
stmt: fix bug of non concurrent security & add double check
2020-06-21 18:01:14 +08:00
askuy
6e4d0917b2
Merge pull request #4023 from flycash/feature/prometheus
Change prometheus patter
2020-06-21 17:39:02 +08:00
Ming Deng
9b43a90138 Change prometheus patter 2020-06-21 17:36:13 +08:00
askuy
b7833fb297
Merge pull request #4021 from flycash/feature/prometheus
Add prometheus support
2020-06-21 17:11:00 +08:00
Ming Deng
16b81d09a7 Add prometheus support 2020-06-21 17:10:34 +08:00
Ming Deng
0056b92d0b
Merge pull request #4007 from flycash/fix3949
Store RouterPattern before filter execute
2020-06-21 17:05:04 +08:00
jianzhiyao
decc75e025 fix bug of non concurrent security & add double check 2020-06-21 16:25:32 +08:00
huija
f2bae3e367 add UT for Scan function 2020-06-19 22:55:40 +08:00
askuy
6eeea141d8
Merge pull request #4018 from flycash/fix/xss
Using HTMLEscapeString in adminui.go to avoid XSS attack
2020-06-19 22:21:51 +08:00
Ming Deng
6c0db4db3d Using HTMLEscapeString in adminui.go to avoid XSS attack 2020-06-19 21:49:17 +08:00
Ming Deng
b9fbcbd906
Merge pull request #4014 from jianzhiyao/develop
over size file do not run openFile
2020-06-19 20:19:16 +08:00
huija
40181c1042 Update redis.go
use `scan` instead of `keys`
2020-06-19 14:21:12 +08:00
qiantao
3879fd9c34 修改测试用例 2020-06-18 17:25:48 +08:00
qiantao
af238ee047 Merge remote-tracking branch 'origin/develop' into go_modules_route_compatibility
# Conflicts:
#	go.mod
#	go.sum
2020-06-18 16:41:03 +08:00
Ming Deng
86935ada01
Merge pull request #3943 from zhlicen/master
#3942 fix encoded url(with slash) router match problem
2020-06-18 16:04:16 +08:00
jianzhiyao
8160059182 big size file lead to memory leak 2020-06-16 14:56:58 +08:00
harry890829
dc70e9fc47 update go test 2020-06-15 18:16:40 +08:00
Ming Deng
bac2b31afe
Merge pull request #3975 from nicowaisman/patch-2
Change permission mask
2020-06-13 23:40:13 +08:00
harry890829
a134cb8d17 update go test 2020-06-11 23:45:06 +08:00
Ming Deng
4ad699b7b8
Merge pull request #3981 from zwei0526/develop
Update parser.go
2020-06-10 16:38:15 +08:00
Ming Deng
14fc935cb6
Merge pull request #4005 from keminar/develop
fix graceful bug
2020-06-10 16:34:32 +08:00
harry890829
d9f262e277 update go test 2020-06-10 12:31:38 +08:00
harry890829
131748bb3d update go.mod&go.sum 2020-06-10 11:34:58 +08:00
harry890829
2c3c66ccea Merge remote-tracking branch 'origin/develop' into develop 2020-06-10 11:16:17 +08:00
harry890829
71cb1379b4 update support bit operation 2020-06-10 11:15:23 +08:00
harry890829
b351f02525 Merge branch 'develop' of https://github.com/astaxie/beego into develop
 Conflicts:
	go.sum
2020-06-10 11:05:57 +08:00
liminggui
8e29300f85 fix graceful bug 2020-06-09 12:20:08 +08:00
flycash
5f31bf45d4 Fix #3949 : store RouterPattern before filter execute so that filter can use the pattern 2020-06-07 23:16:26 +08:00
askuy
3e30f37172
Merge pull request #4006 from flycash/develop
fix CI and UT
2020-06-06 21:16:08 +08:00
flycash
ce4ce74c8d Fix validation test 2020-06-06 20:50:48 +08:00
flycash
ce0e7525ad Fix ES client 2020-06-06 20:14:01 +08:00
flycash
d0b7244d57 Fix ledis 2020-06-06 19:21:57 +08:00
Ming Deng
5100a8c396 fix CI and UT 2020-06-06 18:16:36 +08:00
Ming Deng
b8efb3ef45
Merge pull request #3984 from jianzhiyao/develop
fix bug:static can not real hit cache & memory leak
2020-06-06 13:10:58 +08:00
Ming Deng
ae15b54f83
Merge pull request #3992 from maxshine/fix-3991
[Fix-Issue-3991] Fix Read with SQLite not supporting SELECT FOR UPDAT…
2020-06-06 13:10:08 +08:00
Ming Deng
0dab959c95
Merge pull request #4004 from gokangaroo/develop
avoid `panic: send on closed channel` after closing logger.
2020-06-06 13:09:36 +08:00
Ming Deng
ee615dd08f
Merge pull request #3985 from leapsea/develop
修复多线程下数据库连接异常问题
2020-06-06 12:40:50 +08:00
huija
b879a07b3a avoid panic: send on closed channel after closing logger. 2020-06-04 14:52:54 +08:00
jianzhiyao
c265f6e49c add comment 2020-06-02 20:02:58 +08:00
jianzhiyao
690e91e1b6 static file module:make cache file size and cache file numbers configurable 2020-06-02 18:22:47 +08:00
jianzhiyao
50f71a8a21 fix bug of getting int error 2020-06-02 18:10:17 +08:00
Yang, Gao
677d010d86 [Fix-Issue-3991] Add warn for SQLite Read is invoked isForUpdate=true 2020-06-01 23:12:12 +08:00
Ming Deng
db2a1134ce
Merge pull request #3993 from skanger/develop
fix httplib PostFile method
2020-06-01 22:05:01 +08:00
qiantao
c2771397be delete vendor 2020-06-01 15:06:49 +08:00
qiantao
70733d9810 fix label == `` #4001 2020-06-01 15:06:33 +08:00
Ming Deng
11740cede6
Merge pull request #3996 from bharrat/3995-fix-middleware-not-working-with-graceful
Fixes #3995 Use handlers with middleware when starting Graceful server
2020-05-31 22:23:05 +08:00
qiantao
4ffe26a1d2 for go modules, generate route by GO111MODULE=on 2020-05-22 11:35:45 +08:00
Bharat Patel
075db4773b Fixes #3995 Use handlers with middleware when starting Graceful server 2020-05-18 10:00:14 -07:00
harry890829
2fd9dfca7b update support bit operation 2020-05-18 19:18:35 +08:00
skanger
eea20f6ceb fix httplib PostFile method 2020-05-16 11:00:15 +08:00
Yang, Gao
8055357576 [Fix-Issue-3991] Fix Read with SQLite not supporting SELECT FOR UPDATE syntax 2020-05-15 17:36:01 +08:00
jianzhiyao
9fda81b7f3 modify static cache total size about 100m 2020-05-09 18:24:14 +08:00
jianzhiyao
4b12e053b7 fix 2020-05-09 17:58:10 +08:00
jianzhiyao
0307c8b110 set static file cahce limit:file size & file count 2020-05-09 17:57:00 +08:00
leapsea
867f83de34 修复数据库连接异常问题 2020-05-09 16:31:30 +08:00
jianzhiyao
af19822293 not modify go.mod 2020-05-09 14:06:51 +08:00
jianzhiyao
2449aad105 add cache-hit test example 2020-05-09 10:44:37 +08:00
jianzhiyao
d31975a752 complete test example 2020-05-08 17:35:02 +08:00
jianzhiyao
b28d5e2716 fix bug:static canot real hit cache
opt:reduce risk of memory leak with lru cache
2020-05-08 17:10:19 +08:00
zwei0526
ab33d683ea
Update parser.go
修复genRouterCode方法解析  router 注释(// @router) 单双引号引起的bug
2020-04-26 19:26:10 +08:00
Nico Waisman
f99cbe0fa4
Change permission mask 2020-04-22 08:42:54 -07:00
HANG ZHOU
0aa82d875a
Update input.go 2020-03-05 14:46:17 +00:00
astaxie
8f3d1c5f42
Merge pull request #3922 from BurtonQin/bug-1-2-3-inconsistent-field-protection
cache, context, session: add lock to fix inconsistent field protection
2020-02-22 15:09:25 +08:00
astaxie
2410b364af
Merge pull request #3923 from timchenxiaoyu/develop
fix exist typo
2020-02-22 11:25:13 +08:00
陈晓宇
713503e43d fix exist typo 2020-02-14 16:47:47 +08:00
BurtonQin
cfdd1cd5be cache, context, session: add lock to fix inconsistent field protection 2020-02-10 21:49:46 +08:00
astaxie
0cd80525e7 Merge branch 'develop' 2020-02-07 16:25:41 +08:00
astaxie
de5650b723 version 1.12.1 2020-02-07 16:23:57 +08:00
astaxie
e5e4a3bea7
Merge pull request #3868 from holtyuzhuyanbo/fix_session_destory
fix: session destory
2020-02-07 11:49:54 +08:00
astaxie
90d0b43f34
Merge pull request #3888 from gavin2014/develop
[Fix] Fix create table with SQLite not supporting COMMENT syntax
2020-02-07 11:46:52 +08:00
astaxie
1b7f5ba2c4
Merge pull request #3900 from aixiaoxiang/develop
httplib:fixes network request failed to create an invalid file and automatically created file directory
2020-02-07 11:10:56 +08:00
astaxie
96f01079cb
Merge pull request #3905 from ywk253100/200110_context
Send the request from context rather than the original one to handlers
2020-02-07 11:05:01 +08:00
astaxie
9d4b5b313f
Merge pull request #3911 from liuzhang/develop
验证调整,增加label, xx不能为空
2020-02-07 11:04:11 +08:00
astaxie
b882009979
Merge pull request #3919 from wy65701436/develop-sha256
update hash algorithm for signing the cookie for xsrf token
2020-02-07 11:01:10 +08:00
wang yan
a768bf8f00 update hash algorithm for signing the cookie for xsrf token
Due to the chosen-prefix collision in SHA-1(details at https://sha-mbles.github.io/), SHA-1 hash functions should to be deprecated and SHA-2/SHA-3 should be used instead.

Signed-off-by: wang yan <wangyan@vmware.com>
2020-02-06 17:31:24 +08:00
Liu Zhang
034599ca1d 验证调整,增加label, xx不能为空 2020-01-17 16:47:19 +08:00
Wenkai Yin
5a02c556b2 Send the request from context rather than the original one to handlers
The filters may do some changes to the request, such as putting values in the request's context

Signed-off-by: Wenkai Yin <yinw@vmware.com>
2020-01-10 17:58:00 +08:00
axx
dc5c42e981 httplib:fixes network request failed to create an invalid file and automatically created file directory 2019-12-30 11:24:55 +08:00
大盖文
92a4119258
Update cmd_utils.go
[Fix] Fix create table with SQLite not supporting COMMENT syntax
2019-12-11 16:50:08 +08:00
astaxie
aa90c67a75
Merge pull request #3867 from ywk253100/191119_xsrf
Abort with the pre-defined status code when handling XSRF error
2019-11-29 18:43:02 +08:00
holtyuzhuyanbo
38a144c68f fix: session destory 2019-11-19 21:25:30 +08:00
Wenkai Yin
793047097c Abort with the pre-defined status code when handling XSRF error
As the status codes(422 and 417) are set in the error map, abort with them directly to active the pre-defined error handlers

Signed-off-by: Wenkai Yin <yinw@vmware.com>
2019-11-19 18:55:54 +08:00
astaxie
1923b8c767
Merge pull request #3841 from HKail/develop
添加16开头手机号验证
2019-10-23 22:22:52 +08:00
Allen
fb640f0075 更新16开头手机号的正则测试 2019-10-22 17:07:22 +08:00
Allen
241f10b429 添加16开头手机号验证,162电信,165移动,166/167联通。 2019-10-22 16:58:05 +08:00
Allen
b8d626bbea 添加16开头手机号验证,162电信,165移动,166/167联通。 2019-10-22 16:28:19 +08:00
astaxie
2a6ceca861
Update README.md 2019-10-10 11:23:19 +08:00
astaxie
10236b9f2d
Merge pull request #3814 from cloudzhou/patch-2
leak opened file
2019-10-10 00:48:24 +08:00
dbt4516
b3ae5d4ac6
Update file.go
According to issue#4759 (https://github.com/golang/go/issues/4759) filepath.Walk function in golang cannot handle symbolic path, meanwhile symbolic path for log directory is pretty common used. In such scenario this deleteOldLog function will fail without any error log. Get the real location of the log directory before using walk function can fix this.
2019-10-09 15:53:22 +08:00
wanghz
77fc8e4e38 According to issue#4759 (https://github.com/golang/go/issues/4759) filepath.Walk function in golang cannot handle symbolic path, meanwhile symbolic path for log directory is pretty common used. In such scenario this deleteOldLog function will fail without any error log. Get the real location of the log directory before using walk function can fix this. 2019-10-09 15:33:38 +08:00
cloudzhou
5a5482c77f
leak opened file
should defer file.Close()
2019-09-27 19:27:44 +08:00
astaxie
11774c87a5 update version 1.13 2019-09-19 00:19:33 +08:00
didi
6d47b4a2e0 GetMapData change to read lock 2019-09-09 17:44:10 +08:00
Dennis
8395a26061
Merge pull request #3801 from DennisMao/develop
fix annotation on orm/utils #3777
2019-09-09 00:46:36 +08:00
Razil
4348356d0a fix annotation on orm/utils 2019-09-09 00:47:20 +08:00
colstuwjx
b551949a2b Add PrintStack() while orm abnormally exit. 2019-07-31 14:08:58 +08:00
nuczzz
32cd76396d fix graceful bug 2019-07-27 18:54:13 +08:00
astaxie
5620608418
Update README.md 2019-07-21 22:58:28 +08:00
astaxie
32ee728078
Merge pull request #3586 from astaxie/develop
V1.12.0
2019-07-05 12:26:39 +08:00
astaxie
de7ce2f9b0 v1.12.0 2019-07-05 11:58:41 +08:00
astaxie
d6c2a9fd4b
Merge pull request #3703 from jkylin/develop
email的Attach和AttachFile 的参数检查逻辑有误。len(args) < 1 && len(args) > 2 改为 l…
2019-07-05 11:35:47 +08:00
astaxie
582a4fa34b
Merge pull request #3699 from orgmatileg/develop
router.go: add comment func LogAccess
2019-07-05 11:34:59 +08:00
astaxie
99647986de
Merge pull request #3689 from GeorgeXc/addStmt
Add stmt
2019-07-05 11:34:40 +08:00
BaoyangChai
5bcde306ea Revert "update"
This reverts commit 2909ff336667627a34edd5c9625c1e6812a6a85f.
2019-06-28 23:37:32 +08:00
BaoyangChai
2909ff3366 update 2019-06-28 23:23:01 +08:00
BaoyangChai
40078cba2c update 2019-06-28 23:13:18 +08:00
BaoyangChai
5d0c0a03d7 update 2019-06-28 22:56:32 +08:00
hsht
8cfd7f5c19 email的Attach和AttachFile 的参数检查逻辑有误。len(args) < 1 && len(args) > 2 改为 len(args) < 1 || len(args) > 2 2019-06-28 20:09:23 +08:00
Luqmanul Hakim
62d96c2e93 router.go: add comment func LogAccess 2019-06-25 08:04:21 +07:00
astaxie
e844058aed
Merge pull request #3632 from Wusuluren/develop
fix concurrent map access problem on BeegoInput.data
2019-06-18 12:09:34 +08:00
astaxie
1eab6bb32a
Merge pull request #3669 from xfwduke/develop
fix bugs of ParseForm about time in RFC3339 format
2019-06-18 12:08:55 +08:00
astaxie
c265d32c36
Merge pull request #3685 from Anderson-Lu/fix_orm_datarace
fix orm datarace
2019-06-18 12:05:54 +08:00
BaoyangChai
06692c3e27 update 2019-06-17 23:38:07 +08:00
luxueyan
394a73c75f fix orm datarace 2019-06-14 14:43:02 +08:00
Wusuluren
cbcde8bd1f Merge branch 'develop' of https://github.com/Wusuluren/beego into develop 2019-06-09 22:10:22 +08:00
Wusuluren
b17e49e6aa fix concurrent map access problem on BeegoInput.data 2019-06-09 22:09:38 +08:00
BaoyangChai
873f62edff update 2019-06-09 01:19:17 +08:00
BaoyangChai
cc0eacbe02 update 2019-06-08 23:53:42 +08:00
oberontang
649c5c861d fix bugs of ParseForm about time in RFC3339 format 2019-05-31 15:52:19 +08:00
Faissal Elamraoui
206a7ed1fc
Merge pull request #3662 from npu21/develop
fix typos
2019-05-27 11:07:52 +02:00
张勇
3c046a4dbf fix two typos 2019-05-27 16:38:30 +08:00
astaxie
f2be6af2ca
Merge pull request #3658 from priyesh-lb/patch-1
Beego skipping some migrations
2019-05-18 09:38:09 +08:00
astaxie
804b9769e0
Merge pull request #3642 from GeorgeXc/fixBatchUpdate
Fix BatchUpdate not update the auto_now field
2019-05-18 09:28:22 +08:00
astaxie
585df01899
Merge pull request #3635 from edwardhey/develop
Incr和Decr应该改成排它锁,否则在并发的时候会出现非期望的结果值
2019-05-18 09:27:38 +08:00
astaxie
1a529c061c
Merge pull request #3633 from MarxGo/develop
fix:utils.GetGOPATHs() when go version equal or after go1.10
2019-05-18 09:27:08 +08:00
Priyesh
fcacfc08e3
Beego skipping some migrations
Beego skipping some migrations #3657
2019-05-17 16:19:26 +05:30
BaoyangChai
a0ca3d61d6 update 2019-05-08 23:11:57 +08:00
Edward.Yang
39bd40e512 Incr和Decr应该改成排它锁,否则在并发的时候会出现非期望的结果值 2019-05-01 13:10:21 +08:00
Guo
8748de95c7 fix:utils.GetGOPATHs() when go version equal or after go1.10 func does not return defaultGoPATH() 2019-04-30 06:43:25 +08:00
Wusuluren
0939e8e493 fix concurrent map access problem on BeegoInput.data 2019-04-30 00:15:24 +08:00
hwave
6a33feee46
Merge pull request #1 from astaxie/develop
update
2019-04-29 23:19:27 +08:00
astaxie
58b2ac702c
Merge pull request #3623 from Martinho0330/develop
make routers configurable for beego multi-instance in the same repo
2019-04-29 18:19:22 +08:00
astaxie
175714f69a
Merge pull request #3627 from haleyly/develop
route request put amendment
2019-04-29 18:18:19 +08:00
haley
d5b70118a3 Merge branch 'develop' of https://github.com/haleyLy/beego into dev 2019-04-28 08:51:34 +08:00
haley
a9629f707e route request put amendment 2019-04-28 08:50:30 +08:00
astaxie
6123c72752
Merge pull request #3621 from guanle/guanle-patch-1
Update templatefunc.go  for default value tag
2019-04-27 23:28:35 +08:00
astaxie
56afa5c2bf
Merge pull request #3625 from hsluoyz/develop
remove the 1000-row limit for ORM result set
2019-04-27 23:27:58 +08:00
astaxie
0c576dac82
Merge pull request #3599 from Wusuluren/cache_file
fix bug on cache/file
2019-04-27 23:27:27 +08:00
astaxie
8462372c03
Merge pull request #3598 from Wusuluren/develop
fix race problem on toolbox/task
2019-04-27 23:26:29 +08:00
astaxie
20ff97d53d
Merge pull request #3595 from JessonChan/log_revet
Log revet
2019-04-27 23:26:06 +08:00
astaxie
8ce5b6cc52
Merge pull request #3593 from JessonChan/trace_method
Trace method
2019-04-27 23:25:44 +08:00
Yang Luo
afb787d49d remove the 1000-row limit for ORM result set 2019-04-27 16:58:00 +08:00
hetingyao
0b165b78a1 make routers configurable for beego multi-instance in the same repo 2019-04-22 22:18:37 +08:00
guanle
fa97488bdc
Update templatefunc.go 2019-04-21 10:27:35 +08:00
astaxie
3086081ec0 v1.11.2 2019-04-06 13:50:14 +08:00
Wusuluren
dfab44c24a fix bug on cache/file 2019-04-05 22:32:28 +08:00
Wusuluren
1900246054 fix bug on cache/file 2019-04-05 22:17:56 +08:00
Wusuluren
e980f92c63 fix race problem on toolbox/task 2019-04-05 20:28:24 +08:00
JessonChan
ce3800e3ef // Deprecated: use github.com/astaxie/beego/logs instead. 2019-04-03 14:13:38 +08:00
JessonChan
e3d668f450 revet to log.go
https://github.com/astaxie/beego/issues/3591
https://github.com/astaxie/beego/issues/3588
2019-04-03 14:08:42 +08:00
JessonChan
75b4bc5896 it's no need to override Trace method. 2019-04-03 10:19:09 +08:00
astaxie
c0ecf32d17 update travis 2019-04-02 21:53:01 +08:00
JessonChan
3155f07ccd no need to override Trace method. 2019-03-27 13:43:27 +08:00
JessonChan
02bead5097 handle trace request must NOT CACHE
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control
2019-03-27 13:40:34 +08:00
JessonChan
e8b29c9fd1 handle trace request 2019-03-27 13:34:46 +08:00
astaxie
610f27d684
Merge pull request #3530 from GeorgeXc/develop
[orm] add ignore auto_now_add field when update
2019-03-27 00:14:07 +08:00
astaxie
59466f6678
Merge pull request #3554 from grahamjamesaddis/travis-ci-build
Allow forked beego project to pass travis ci builds
2019-03-26 19:24:06 +08:00
astaxie
3ddd8f860e
Merge pull request #3561 from JessonChan/develop
refactor color logger
2019-03-26 19:23:14 +08:00
astaxie
8535ec0819
Merge pull request #3567 from bsdelf/feature/ensure-custom-error-handler
Ensure custom error handler is called
2019-03-26 19:22:54 +08:00
astaxie
f294121ab7
Merge pull request #3583 from maxshine/develop
[Fix] Fix the issue that genRouterCode results in @Import annotations getting overwritten
2019-03-26 19:13:44 +08:00
GeorgeXc
0b8ebaf387
Update db.go 2019-03-26 01:00:04 +08:00
Yang, Gao
3b00cfccec [Fix] Fix the issue that genRouterCode incorrect logic results in @Import annotations getting overwritten 2019-03-24 14:41:28 +08:00
BaoyangChai
005391be81 update 2019-03-23 00:33:26 +08:00
Faissal Elamraoui
bc8fffe347
Merge pull request #3571 from dxas90/patch-1
Fixes #3570
2019-03-14 19:16:15 +01:00
Daniel Ramirez Grave de Peralta
914bbfd710
Update apiauth.go fixed infinite recursive call 2019-03-14 09:14:12 -04:00
Yanhui Shen
be31bd2bbd Ensure custom error handler is called 2019-03-13 16:24:04 +08:00
JessonChan
95ff817019 undefined: beego.BeeLogger fixed 2019-03-13 09:41:13 +08:00
JessonChan
ea91e7638c move log function to log package 2019-03-12 17:01:23 +08:00
JessonChan
4564e9810c logger_test imported and not used: "bytes" 2019-03-12 16:36:00 +08:00
JessonChan
44a1a8f6be println is builtin function 2019-03-12 15:51:43 +08:00
JessonChan
9cecb22170 NewAnsiColorWriter remove 2019-03-12 15:13:54 +08:00
JessonChan
7693502aaa logAdapter is more readable 2019-03-12 13:20:13 +08:00
JessonChan
c0fae547e9 remove ansicolor code,import ansicolor package 2019-03-12 12:14:09 +08:00
JessonChan
0ba77a0d87 colorful is the switch to level label 2019-03-12 12:12:59 +08:00
JessonChan
661dcbb6ca router logger modify 2019-03-12 12:11:25 +08:00
JessonChan
578440a18d add ansicolor to beego 2019-03-12 12:09:41 +08:00
JessonChan
93485df3d2 color should be false by default otherwise the http logger's color would be wrong 2019-03-08 14:42:06 +08:00
JessonChan
121fab61f1 ResetColor function 2019-03-08 12:18:45 +08:00
JessonChan
915eec7943 Merge branch 'develop' of github.com:astaxie/beego into develop 2019-03-08 12:16:00 +08:00
JessonChan
8432a1c758 better comment for color map 2019-03-08 12:10:57 +08:00
JessonChan
4a5e108527 logger color function refactor,easy to read and run more quickly 2019-03-08 11:50:30 +08:00
JessonChan
6dd5171fdf logger color function refactor,easy to read and run more quickly 2019-03-08 11:08:39 +08:00
astaxie
c2b6cb5c3a
Merge pull request #3560 from JessonChan/develop
TestToJson bug fixed
2019-03-08 00:18:39 +08:00
JessonChan
1f93040af6 Merge remote-tracking branch 'upstream/develop' into develop 2019-03-07 18:07:37 +08:00
JessonChan
52f8ccd06c TestToJson bug fixed 2019-03-07 17:15:30 +08:00
astaxie
3b86feab8a
Merge pull request #3555 from hellomrleeus/develop
spelling mistake of word "Header"
2019-03-06 09:58:54 +08:00
hellomrlee
aba51d99a1 spelling mistake of word "Header" 2019-03-04 11:05:29 +08:00
grahamjamesaddis
8454e8417e Allow forked beego project to pass travis ci builds 2019-03-01 14:00:20 +00:00
astaxie
422e8285b5
Merge pull request #3494 from nuczzz/develop
simplify beego grace with http.Shutdown
2019-02-26 16:31:40 +08:00
astaxie
bb6ca6b100
Merge pull request #3522 from saromanov/check-input-data
SessionRead: check of the length for input sid variable
2019-02-25 23:17:57 +08:00
astaxie
1483c1f545
Merge pull request #3524 from Quasilyte/quasilyte/bytesreader
config/yaml: s/bytes.NewBuffer/bytes.NewReader/
2019-02-25 23:16:39 +08:00
astaxie
3d6a68de77
Merge pull request #3535 from gadelkareem/develop
Make LogAccess() function public
2019-02-25 23:11:14 +08:00
astaxie
387d387080
Merge pull request #3547 from snedzad/patch-1
Register .gohtml extension
2019-02-25 11:43:37 +08:00
Nedzad Smajic
94ed35e781
Register .gohtml extension
Goland as of 2018.3 seems to support only '.tpl.gohtml" and ".gohtml" templates. The regular ".tpl" templates will be rendered as plain text files which is not acceptable.
2019-02-23 22:49:32 +01:00
Waleed Gadelkareem
8995b291a9 Make LogAccess public 2019-02-14 16:30:25 +01:00
Waleed Gadelkareem
1942438b22
Merge pull request #3 from astaxie/develop
develop
2019-02-14 16:23:35 +01:00
astaxie
40d653e659
Merge pull request #3533 from tvanriper/patch-1
APIBaiscAuth is misspelling of APIBasicAuth
2019-02-13 02:10:25 +08:00
Joseph Edwards Van Riper III
ddcd28e67f
APIBaiscAuth is misspelling of APIBasicAuth
Corrected APIBaiscAuth to APIBasicAuth.  Maintained old name (forwarding to new one) for those still using the previous API function name.
2019-02-12 13:00:11 -05:00
BaoyangChai
65f587d5e9 fix ineffectual assignment 2019-02-12 19:05:22 +08:00
BaoyangChai
2fefd8cbbf update len 2019-02-12 18:53:34 +08:00
BaoyangChai
ba17bdd366 add ignore auto_now_add field when update 2019-02-12 18:05:29 +08:00
Iskander Sharipov
c998e52cc0 config/yaml: s/bytes.NewBuffer/bytes.NewReader/
When io.Reader is required out of []byte,
it's better to use bytes.NewReader than bytes.NewBuffer.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2019-02-10 20:37:43 +03:00
Faissal Elamraoui
3224369ac9
Merge pull request #3523 from Quasilyte/quasilyte/boolExprSimplify
Simplify boolean expressions
2019-02-09 16:16:31 +01:00
Iskander Sharipov
67666dbe0f all: simplify boolean expressions
- !(a == b) => a != b
- !(a != b) => a == b

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2019-02-09 17:18:59 +03:00
Sergey
d7430eb921
SessionRead: check of the length for input sid variable 2019-02-04 11:03:27 +05:00
astaxie
26a6b426f1
Merge pull request #3487 from duyazhe/patch-1
Update orm_log.go
2019-02-04 11:26:42 +08:00
astaxie
6f35ce67f7
Merge pull request #3493 from bharat-p/3492-add-db-stats-to-ormer
Add DBStats method wrapper to provide sql.DBStats when using ormer
2019-02-04 11:24:13 +08:00
astaxie
3406d58797
Merge pull request #3503 from wtospit/develop
fix: when parse post form it didnt parse fields correctly
2019-02-04 11:23:23 +08:00
astaxie
7925458fc0
Merge pull request #3502 from Quasilyte/patch-1
cache: remove excessive type assertions
2019-02-02 16:43:04 +08:00
astaxie
b6854aaf9f
Merge pull request #3506 from DennisMao/hotfixFileCachePanic
fix panic cause by the map
2019-02-02 16:38:11 +08:00
astaxie
656f595226
Merge pull request #3508 from Quasilyte/patch-2
replace unchecked Compile calls with MustCompile
2019-02-02 16:36:15 +08:00
astaxie
280aaf9d3b
Merge pull request #3519 from zav8/add_support_for_pointer_fields
add support for pointer fields of structs to method QueryRows()
2019-02-02 16:35:41 +08:00
zav8
7abdb05f91 little fix 2019-02-01 15:39:40 +08:00
zav8
af4464ce58 add support for pointer fields of structs to method QueryRows() 2019-02-01 15:27:10 +08:00
Iskander (Alex) Sharipov
6ca0978777
replace unchecked Compile calls with MustCompile
For constant patterns and especially when errors are ignored,
`regexp.MustCompile` is a better choice than `regexp.Compile`.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2019-01-26 14:13:53 +03:00
DennisMao
8506194d2c fix panic cause by the map 2019-01-25 19:08:39 +08:00
Witaya Tospitakkul
3bd7614ade refactoring code after discussion 2019-01-25 11:00:24 +07:00
Witaya Tospitakkul
bd1b421491 fix: adding test for issue due to testing is not reflect changed 2019-01-25 09:04:01 +07:00
Witaya Tospitakkul
920207f72c add testing for ParseForm when form post has a slice in body 2019-01-25 00:38:14 +07:00
Witaya Tospitakkul
12fdc04f1b fix: when parse post form it didnt parse fields which have same name but the first index is empty but another is not 2019-01-25 00:15:40 +07:00
astaxie
d0c744ae6a
Merge pull request #3499 from JessonChan/develop
fix download filename(chinese) bug
2019-01-24 17:27:29 +08:00
Iskander (Alex) Sharipov
dc07fa7085
cache: remove excessive type assertions
Assign type switch variable to get properly-typed value
inside case clauses.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2019-01-24 08:52:30 +03:00
JessonChan
1c893996c0 improve the download func code 2019-01-23 12:36:14 +08:00
JessonChan
a9ffc2a078 https://github.com/astaxie/beego/issues/3446
Use UTF-8 as the encoding of the "filename*" parameter, when
                           present, because at least one existing implementation only
                           implements that encoding.
2019-01-23 12:30:57 +08:00
astaxie
712bbfe575
Merge pull request #3498 from JessonChan/develop
change gosimple to staticcheck
2019-01-23 11:31:37 +08:00
JessonChan
0145fe3486 remove SA1024 staticchek 2019-01-22 20:52:06 +08:00
JessonChan
2a579eb27c staticcheck checks -ST1003 remove 2019-01-22 20:41:07 +08:00
JessonChan
5b42afa324 modiyf staticcheck checks 2019-01-22 20:30:05 +08:00
JessonChan
97713849a1 delete stackcheck config file and ignore some staticcheck checks 2019-01-22 20:21:00 +08:00
JessonChan
abc9c38224 ignore some staticcheck checks 2019-01-22 20:04:30 +08:00
JessonChan
f237ff049a redis_sentinel test ignore 2019-01-22 19:45:32 +08:00
JessonChan
00264650b5 modify travis and redis_sentinel test 2019-01-22 19:29:53 +08:00
JessonChan
2956d33bab no need gosimple 2019-01-22 19:12:25 +08:00
JessonChan
c3eca637fb no need gosimple 2019-01-22 19:10:23 +08:00
JessonChan
0d54bbff02 make staticcheck happy 2019-01-22 19:09:57 +08:00
JessonChan
e65a9cbc00 Gosimple has been deprecated. Please use staticcheck instead. 2019-01-22 18:01:14 +08:00
JessonChan
3ed82c0882 Gosimple has been deprecated. Please use staticcheck instead. 2019-01-22 17:43:55 +08:00
JessonChan
475feb7e24 camel name style 2019-01-22 16:25:17 +08:00
JessonChan
30b80cba92 errors is better style 2019-01-22 16:23:10 +08:00
nuczzz
fe519bd2a0 update tls KeepAlive setting 2019-01-20 11:17:10 +08:00
Bharat Patel
f508f8d959 Nil check 2019-01-18 16:51:40 -08:00
nuczzz
e295c3c7c3 add shutdown log 2019-01-18 19:50:22 +08:00
nuczzz
313be996cd call cancel after shutdown 2019-01-18 19:33:45 +08:00
Bharat Patel
2ae480556d Add DBStats method wrapper to provide sql.DBStats when using ormer 2019-01-17 09:56:42 -08:00
nuczzz
7173fd7490 modify http graceful 2019-01-17 20:17:57 +08:00
duyazhe
d792536c23
Update orm_log.go
orm log支持用户自定义函数处理
2019-01-14 15:14:11 +08:00
astaxie
80aabdd372
Merge pull request #3472 from sangheee/develop
fix: negative WaitGroup counter has not been resolved yet.
2019-01-08 23:54:40 +08:00
astaxie
6892369cc6
Merge pull request #3464 from zhl11b/develop
手机号起始三位补全
2019-01-08 23:54:00 +08:00
astaxie
5b80a56c36
Merge pull request #3468 from DennisMao/hotfix/UpdateDependencyGoes
update dependency
2019-01-08 23:52:39 +08:00
sanghee
bf15535a5b fix panic: sync: negative WaitGroup counter 2019-01-03 22:44:32 +09:00
DennisMao
edb1c52dee fix function changes 2019-01-02 17:01:46 +08:00
DennisMao
6e16b8cdcf fix ci losing dependency 2019-01-02 16:46:27 +08:00
DennisMao
24215fb3eb update dependency 2019-01-02 15:37:41 +08:00
zhl11b
d02699a189 add new test case for china mobile phone 2018-12-30 20:51:21 +08:00
zhl11b
2034d1b101 联通171,175 电信173 2018-12-29 17:41:59 +08:00
astaxie
5fe19d639f
Merge pull request #3456 from japettyjohn/master
Fix bug in memcache sessions
2018-12-28 22:35:11 +08:00
James Pettyjohn
1dea80d4ea Fixed error handling in memcache sessions 2018-12-27 16:20:26 -08:00
astaxie
28f0008075
Merge pull request #3434 from zav8/add_sql_null_support
Add support for field of type sql.NullXxx in rawSet.setFieldValue()
2018-12-19 22:26:23 +08:00
zav8
ffe1b00baf Merge branch 'develop' of https://github.com/astaxie/beego into add_sql_null_support 2018-12-18 10:41:17 +08:00
zav8
d2c289193a add test case for QueryRow and QueryRows 2018-12-18 10:37:41 +08:00
astaxie
f867583256
Merge pull request #3433 from DennisMao/FixOrmDescriptionTag
Fix Issue #3337
2018-12-18 09:20:36 +08:00
astaxie
98dfb92e17
Merge pull request #3443 from zhiquan911/develop
add GetProvider
2018-12-18 09:10:17 +08:00
郭一鸣
c8f22be675 Add redis sentinel session support (#3427)
Add Redis Sentinel session support
2018-12-17 14:47:47 +01:00
Chance
f03a7d1128
add GetProvider 2018-12-13 15:37:19 +08:00
zav8
6da4a66c20 merge switch cases 2018-12-06 16:09:39 +08:00
zav8
5e4241fc87 add support for field of type sql.NullXxx in rawSet.setFieldValue() 2018-12-06 16:07:07 +08:00
DennisMao
bf468c8d0c fix format 2018-12-06 10:57:32 +08:00
DennisMao
0d77a3f8d2 FixOrmDescrptionTag 2018-12-06 10:49:50 +08:00
astaxie
1b6edafc96
Merge pull request #3412 from astaxie/develop
v1.11.1
2018-11-30 21:54:26 +08:00
astaxie
8152ade1b6
Merge pull request #3419 from xpzouying/close_fs_when_is_not_nil
Close fs when is not nil
2018-11-30 16:57:49 +08:00
astaxie
6350f8b904
Merge pull request #3420 from xpzouying/format_list_travis_yml
format list in .travis.yml
2018-11-30 16:57:25 +08:00
astaxie
0c5398a19c update travis 2018-11-30 16:42:44 +08:00
astaxie
4b656268d3 travis 2018-11-28 16:17:53 +08:00
astaxie
10729a1fc5 update vendor & module 2018-11-28 16:05:15 +08:00
Ying Zou
cdb3ef808f format list in .travis.yml 2018-11-28 08:59:27 +08:00
Ying Zou
a5a2471f2c close fs only when fs open without error
panic when close nil filesystem
2018-11-28 08:55:20 +08:00
astaxie
6282747f6d update vendor 2018-11-27 14:11:14 +08:00
astaxie
d5fd5cad38
Merge pull request #3417 from xpzouying/update_code_format
better format
2018-11-27 14:01:59 +08:00
Ying Zou
fab7c6b6d0 better format
- add comments for public function
- format import order in admin.go
- better format for NewControllerRegister in router.go
2018-11-26 23:19:05 +08:00
astaxie
42ade6aa49 v1.11.1 2018-11-22 13:10:52 +08:00
astaxie
55d9b69cd9 update mod 2018-11-22 13:08:39 +08:00
astaxie
2a8d6f943f
Merge pull request #3408 from nlimpid/develop
add different column name parse strategy
2018-11-21 17:18:39 +08:00
nlimpid
6b0155c4fb add different column name parse strategy 2018-11-20 22:47:56 +08:00
astaxie
e22a5143bc
Merge pull request #3403 from nlimpid/develop
add context for db operation
2018-11-20 15:44:25 +08:00
astaxie
a17eb54515
Merge pull request #3405 from coldnight/feature-add-elapsed-in-response
Add .Elapsed in context.ResponseWriter for monitor purpose
2018-11-20 15:39:13 +08:00
nlimpid
d5cf1050db check qs is nil before get forContext 2018-11-19 23:42:56 +08:00
wanghui
b021686521
Add .Elapsed in context.ResponseWriter for monitor purpose
With this commit we can record per requests's elapsed time,
so we can easy to monitor that by use a filter.
2018-11-19 16:38:14 +08:00
astaxie
b0e2bbce2a
Merge pull request #3391 from astaxie/develop
V1.11.0
2018-11-19 14:40:43 +08:00
astaxie
7a50ea7e36
Merge pull request #3395 from astaxie/AddTestForSnakeString
#3192 AddTestSnakeString
2018-11-18 21:59:48 +08:00
astaxie
3070cfc60b
Merge pull request #3396 from astaxie/FixAnnotationOnSnakeString
Fix #3192
2018-11-18 21:59:35 +08:00
nlimpid
e56d1b718f add context for db operation 2018-11-18 21:54:25 +08:00
Dennis
c4c3067a31
Update utils.go 2018-11-15 15:16:41 +08:00
Dennis
81346fe641
Update utils_test.go 2018-11-15 14:50:38 +08:00
astaxie
1a66ad56c6
Merge pull request #3317 from HSoshiant/master
Lock
2018-11-14 19:24:23 +08:00
astaxie
31f2adb79d
Update session.go 2018-11-14 19:24:10 +08:00
astaxie
f514ae309b
Update session.go 2018-11-14 19:23:10 +08:00
astaxie
277d3d98e3 v1.11.0 2018-11-14 17:01:12 +08:00
astaxie
2c46877b36
Merge pull request #3390 from astaxie/FixDataRaceOnCache
Fix  #3354
2018-11-14 15:58:20 +08:00
astaxie
cfe54a02c5
Merge pull request #3388 from s00500/develop
Closes #2515 Autodetect timezone in NewOrmWithDB()
2018-11-13 16:48:18 +08:00
astaxie
55f390d08a
Merge pull request #3387 from wuyumin/master
dynamically add task #2708
2018-11-13 14:51:41 +08:00
astaxie
cf31222643
Merge pull request #3386 from DennisMao/AddTransportSetting
add transport setting
2018-11-13 14:50:28 +08:00
Dennis
9e036bcab5
Update memory.go 2018-11-13 14:43:23 +08:00
d02170e3cb
Closes #2515 Autodetect timezone in NewOrmWithDB() 2018-11-12 10:18:05 +01:00
Yumin Wu
2d6f1af1a5 dynamically add task 2018-11-12 17:17:06 +08:00
Dennis
430457609f
Update httplib_test.go 2018-11-12 13:04:17 +08:00
astaxie
0333e26b3e
Merge pull request #3382 from lxShaDoWxl/add_custom_fs_template
Add custom fs template
2018-11-10 22:44:28 +08:00
Viktor Vassilyev
d0d28566b9 chore(GoMod): add dependency go-bindata-assetfs in vendor dir 2018-11-10 13:41:47 +06:00
Viktor Vassilyev
872b787e6c refactor(FileSystem): add comments function 2018-11-10 12:34:53 +06:00
Viktor Vassilyev
01a99edf80 chore(GoMod): add dependency go-bindata-assetfs 2018-11-10 12:26:19 +06:00
Viktor Vassilyev
6050d37d2a Merge remote-tracking branch 'me/develop' into add_custom_fs_template 2018-11-10 11:39:28 +06:00
astaxie
876dce8e54 fix the routerInfo is nil 2018-11-09 18:03:26 +08:00
astaxie
24885c28f2 fix the comments update 2018-11-09 17:54:20 +08:00
astaxie
5ea04bdfd3 update mod 2018-11-09 12:37:28 +08:00
astaxie
9fdc1eaf3a
Merge pull request #3352 from SongLiangChen/develop
add sessionid prefix
2018-11-08 23:29:05 +08:00
astaxie
6b5a70d246
Merge pull request #3378 from nukc/develop
orm: support filter raw sql
2018-11-08 23:28:30 +08:00
astaxie
8391d26220
Merge pull request #3383 from LockGit/develop
security question, fix arbitrary file read
2018-11-08 23:21:18 +08:00
Viktor Vassilyev
f193e313a3 refactor(FileSystem): using single-line if 2018-11-07 20:21:34 +06:00
Viktor Vassilyev
9ac4928113 refactor(Template): a detailed description of the error 2018-11-07 20:20:10 +06:00
lock
9865779f14 security question, fix arbitrary file read 2018-11-07 11:31:27 +08:00
Viktor Vassilyev
aa6d0f9f0b fix(Template): correct check error 2018-11-06 21:40:43 +06:00
Viktor Vassilyev
68b0bd98fd fix(Template): error handling when reading files 2018-11-06 20:41:05 +06:00
Viktor Vassilyev
3447798494 fix(Template): dependencies in travis 2018-11-06 20:18:48 +06:00
Viktor Vassilyev
ca1b96f986 feat(Template): use interface http.FileSystem 2018-11-06 20:06:21 +06:00
Viktor Vassilyev
771fe35431 feat(Template): testing fs bindata 2018-11-05 22:58:59 +06:00
Viktor Vassilyev
2f00ad1602 fix(Template): close open file 2018-11-05 22:51:20 +06:00
Viktor Vassilyev
f740b71ded fix(Template): remove duplicate check open/exists 2018-11-05 21:08:03 +06:00
Viktor Vassilyev
7aae58a543 feat(Template): create interface FileSystem for to create custom fs 2018-11-05 21:05:19 +06:00
SongLiang
c8da875f83
add sessionId prefix 2018-11-05 09:51:27 +08:00
SongLiang
501d8a97f6
add sessionId prefix 2018-11-05 09:50:19 +08:00
nukc
736e66fcda orm: support filter raw sql 2018-11-05 03:47:21 +08:00
SongLiang
d3ad810f16
add sessionId prefix 2018-10-29 13:35:31 +08:00
SongLiang
abc8b78065
add sessionId prefix 2018-10-29 12:18:06 +08:00
astaxie
f64e6b72e9
Merge pull request #3362 from SmartBrave/develop
modify qbs to qps
2018-10-28 20:01:23 +08:00
astaxie
4e83b4400a
Merge pull request #3371 from HaraldNordgren/go_versions
Bump Go versions and use 1.n.x to get latest minor versions
2018-10-28 19:49:27 +08:00
Harald Nordgren
f6f61513a1 Bump Go versions and use 1.n.x to get latest minor versions 2018-10-28 00:58:36 +02:00
yangzhiyong
8217817a0b modify qbs to qps 2018-10-24 10:38:59 +08:00
astaxie
833f54d818
Merge pull request #3319 from Colstuwjx/annotated-filter
Annotated filter
2018-10-23 13:45:18 +08:00
astaxie
706c086bc5
Merge pull request #3345 from dingyuanhong/develop
fix / can use dynamic directory
2018-10-23 13:43:45 +08:00
SongLiangChen
187add9b84 add sessionid prefix 2018-10-10 11:02:45 +08:00
astaxie
5b8e468a13
Merge pull request #3344 from akhedrane/patch-1
duo to #3278 numRow should be 0
2018-10-05 21:16:18 +08:00
dingyuanhong
dff9c8f5fa fix / can use dynamic directory 2018-10-01 15:16:35 +08:00
Atallah khedrane
21a8623002
duo to #3278 numRow should be 0 2018-09-30 10:45:18 +01:00
astaxie
ea9c5822e6
Merge pull request #3292 from SongLiangChen/master
Read over 4096 length values
2018-09-30 16:03:45 +08:00
astaxie
ad0d166d46
Merge pull request #3295 from GNURub/feature/outputWithformat
feature/outputwithformat
2018-09-30 16:01:07 +08:00
astaxie
2c2ace9a60
Merge pull request #3313 from oiooj/pr-module
support go modules
2018-09-30 15:55:57 +08:00
astaxie
8134a89e81
Merge pull request #3333 from akhedrane/patch-1
Return error when wrong filtering field
2018-09-30 15:45:23 +08:00
astaxie
e342a0099f
Merge pull request #3340 from GNURub/feature/update-travis
Add go 1.11 version
2018-09-30 15:44:46 +08:00
astaxie
c4ed5030da
Merge pull request #3339 from GNURub/hotfix/redis-uri
Support redis URI format
2018-09-30 15:43:41 +08:00
astaxie
7b9c24567d
Merge pull request #3335 from GNURub/hotfix/ranking-response-times
Added link to time ranking
2018-09-30 15:42:05 +08:00
Ruben Cid
6906c5ce30 Updated travis go version 2018-09-27 18:27:38 +02:00
Ruben Cid
e4605f232b Support redis URI 2018-09-26 18:05:09 +02:00
Ruben Cid
6092e737a1 Added link to ranking 2018-09-24 18:33:56 +02:00
Atallah khedrane
0e4d954fa7
Return error when wrong filtering field
When end user put wrong filtering field ORM should return error instead of Panic()
so developers can handle this error.
2018-09-23 12:18:15 +02:00
Colstuwjx
1cbba4d56f Add annotated filter, support @Import, @Filter.
Signed-off-by: Colstuwjx <Colstuwjx@gmail.com>
2018-09-07 15:59:57 +08:00
kun
cf5d1f3f3c support go modules 2018-09-05 14:05:16 +08:00
Hossein Karimy
1097ac3682 GetProvider 2018-08-28 15:12:28 -04:00
Ruben Cid
755cc98ef7 Fix content type 2018-08-21 12:32:16 +02:00
Ruben Cid
5c407ff2e3 Add map shortcut and ServeFormatted method in output 2018-08-20 22:55:50 +02:00
SongLiangChen
8f455ef199 Read over 4096 length values 2018-08-17 11:40:00 +08:00
astaxie
7e0649d661
Merge pull request #3289 from nezorflame/patch-1
Remove panic from Redirect()
2018-08-16 09:22:22 +08:00
Ilya Danilkin
1a3dcb4f84
Remove panic from Redirect()
This `panic(ErrAbort)` is unnecessary in `Redirect` function and causes problems in the production code.
2018-08-12 05:11:03 +03:00
astaxie
b606f1f73f
Merge pull request #3283 from JessonChan/develop
typo fixed
2018-08-09 17:05:25 +08:00
astaxie
8241f219fd
Merge pull request #3278 from hurisheng/revert-3247-develop
Revert "send ErrNoRows if the query returns zero rows ... in method orm_query…"
2018-08-09 17:05:01 +08:00
hurisheng
dea45a3d6c fix TestAll() 2018-08-07 16:36:27 +08:00
JessonChan
34a812d45f typo fixed
#3260
2018-08-07 12:08:15 +08:00
astaxie
842336834f
Merge pull request #3275 from WiFeng/master
fix bug of tasks that only some but not all are executed
2018-08-07 10:07:29 +08:00
astaxie
58fe012446
Merge pull request #3274 from gombaniro/improvement/make-TestSet-on-map-self-contained
breaks dependency on TestNewBeeMap Testcase
2018-08-07 10:02:29 +08:00
astaxie
bf0d40bca6
Merge pull request #3280 from GNURub/feature/pusher
Add access to pusher
2018-08-07 09:58:56 +08:00
Ruben Cid
48e6658eca Add access to pusher 2018-08-03 12:33:46 +02:00
Hu Risheng
1bd3fb7a33
Revert "send ErrNoRows if the query returns zero rows ... in method orm_query…" 2018-08-03 13:35:48 +08:00
liuweifeng
d86410a631 fix bug of tasks that only some but not all are executed 2018-08-01 11:20:22 +08:00
Jean Claude
6b62502b99 breaks rely on TestNewBeeMap 2018-08-01 10:24:39 +08:00
astaxie
053a075344
Merge pull request #3271 from astaxie/develop
add vendor gopkg.in/yaml.v2
2018-07-31 21:18:48 +08:00
astaxie
9dd7d19ce7 add vendor gopkg.in/yaml.v2 2018-07-31 21:18:07 +08:00
astaxie
efe0f67388
Merge pull request #3267 from astaxie/develop
beego 1.10.1
2018-07-31 20:52:47 +08:00
astaxie
de66d2bdfd beego 1.10.1 2018-07-31 20:09:08 +08:00
astaxie
0e4fe4d177
Merge pull request #3270 from astaxie/revert-3269-master
Revert "hible"
2018-07-31 20:07:18 +08:00
astaxie
6d84db1e93
Revert "hible" 2018-07-31 20:07:03 +08:00
astaxie
2486f3826a
Merge pull request #3269 from 514366607/master
hible
2018-07-31 20:06:55 +08:00
astaxie
d7b8aa8b52 only add golang.org vendor 2018-07-31 19:25:43 +08:00
hible
c7c0b01ec5 hible
cache add function
// IncrBy increase counter by num.
IncrBy(key string, num int)
// DecrBy decrease counter by num.
DecrBy(key string, num int)
2018-07-31 17:19:09 +08:00
astaxie
6d69047fff update go vet 2018-07-30 15:13:04 +08:00
astaxie
787ab12605 Merge branch 'develop' of https://github.com/astaxie/beego into develop 2018-07-30 15:01:58 +08:00
astaxie
f4112accef update go vet 2018-07-30 15:01:49 +08:00
astaxie
42c394e28b
Merge pull request #3263 from guomao545/master
Support return middle level value
2018-07-30 12:27:05 +08:00
astaxie
5051d902fb
Merge pull request #2986 from oxgo/hourlylog
add hourly log rotate
2018-07-30 12:26:37 +08:00
astaxie
48acfa08be add vendor 2018-07-30 12:05:51 +08:00
guomao545
39fc30b8b2
Support return middle level value
fix multilevel yaml config can't correct return middle level value bug
2018-07-27 15:33:24 +08:00
two
046cb248e0 edit test case 2018-07-26 15:08:14 +08:00
two
31c746d9d7 fix all confict 2018-07-26 14:34:25 +08:00
two
38a2f32252 fix one confict 2018-07-26 14:29:26 +08:00
astaxie
d55f54a8ab
Merge pull request #3149 from liaoishere/feature/support-begintx
Support DB.BeginTx in go 1.8
2018-07-23 20:25:17 +08:00
Penghui Liao
feb0e67fd7 upgrade go version from 1.9.2 to 1.9.7 in test env.
upgrade to avoid bug: https://github.com/golang/go/issues/22976

Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-23 15:58:12 +08:00
astaxie
a09bafbf2a
Merge pull request #3233 from astaxie/develop
beego 1.10.0
2018-07-21 15:55:28 +08:00
astaxie
03de7456ca
Merge pull request #3250 from 0x0400/develop
acquire lock when access config data
2018-07-21 15:25:23 +08:00
Xingang Zhang
78f2fd8d14 acquire lock when access config data 2018-07-21 14:56:09 +08:00
astaxie
a048ed51a7 ready to release 1.10.0 2018-07-21 09:29:00 +08:00
astaxie
164a9231e8
Merge pull request #3249 from GNURub/feature/autocert
Feature/autocert
2018-07-21 09:20:07 +08:00
Ruben Cid
aaa7e33778 Autocert ok 2018-07-20 19:54:25 +02:00
Ruben Cid
f7008e2877 Removed patch 2018-07-20 19:02:09 +02:00
Ruben Cid
cf6e825547 Domains 2018-07-20 18:59:45 +02:00
Ruben Cid
38f9a3c49e AutoCert 2018-07-20 18:53:57 +02:00
astaxie
f18283a517
Merge pull request #3181 from GNURub/feature/YAML
Feature/yaml
2018-07-20 23:41:15 +08:00
astaxie
61aec396e0
Update .travis.yml 2018-07-20 23:40:11 +08:00
astaxie
5ba9e63086
Merge branch 'develop' into feature/YAML 2018-07-20 23:24:51 +08:00
astaxie
5acc56648d
Merge branch 'develop' into feature/support-begintx 2018-07-20 23:16:12 +08:00
astaxie
bc773039ca
Merge pull request #2997 from DennisMao/master
fix the model can not be registered correctly on Ubuntu 32bit
2018-07-20 23:14:41 +08:00
astaxie
868fc2a29f fix go1.10.3 orm test failed 2018-07-20 22:45:44 +08:00
astaxie
81f69f12ab Merge branch 'develop' of https://github.com/astaxie/beego into develop 2018-07-20 22:30:25 +08:00
astaxie
0711c3289f fix the orm test 2018-07-20 19:58:56 +08:00
Penghui Liao
b8868d6d2d remove unnecessary conversion
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-20 17:07:17 +08:00
Penghui Liao
30bbc81a2e fix test case that calls All()
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-20 16:51:36 +08:00
Penghui Liao
1a3f1d66c1 rename orm_go18.go to orm.go
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-20 16:36:06 +08:00
Penghui Liao
6bdd152d91 upgrade postgres in travis
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-20 16:36:06 +08:00
Penghui Liao
443c77b303 support DB.BeginTx of golang 1.8
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-20 16:36:06 +08:00
Penghui Liao
0dff771707 fix unquoted identifier that may be misleading in postgres
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
2018-07-20 16:36:06 +08:00
astaxie
c9b6e4f825
Merge pull request #2981 from TankTheFrank/fix_template_render_with_automatic_parameter_routing
fixes template rendering with automatic mapped parameters (see #2979)
2018-07-20 15:39:10 +08:00
astaxie
abd02c7de4
Merge pull request #2985 from terryding77/fix_orm_Field_SetRaw_function_error_judge_problem
fix orm fields SetRaw function error judge problem
2018-07-20 15:36:40 +08:00
astaxie
eb4e0e4030
Merge pull request #3022 from chenpeiyuan/develop
do html escape before display path, avoid xss
2018-07-20 15:33:12 +08:00
astaxie
96dffcd27f
Merge pull request #3105 from ckahi/hotfix_log_dir
auto create log dir
2018-07-20 15:32:42 +08:00
astaxie
0d0d87f600 Merge branch 'develop' of https://github.com/astaxie/beego into develop 2018-07-20 15:25:04 +08:00
astaxie
2c779a4287
Merge pull request #3141 from gadelkareem/patch-2
Improve access log
2018-07-20 15:20:15 +08:00
astaxie
f25893832f
Merge pull request #3142 from amitash1109/fix_response_http_code
Fix response http code
2018-07-20 15:18:54 +08:00
astaxie
af73a2d515
Merge branch 'develop' into fix_response_http_code 2018-07-20 15:18:30 +08:00
astaxie
67a6b8723c
Merge pull request #3146 from Wang-Kai/master
Add code style for logs README
2018-07-20 15:17:31 +08:00
astaxie
fdccd85330
Merge pull request #3152 from joshtechnologygroup/staticfile_unexpected_eof_bug_gix
[#2973] Fix Unexpected EOF bug in staticfile
2018-07-20 15:09:07 +08:00
astaxie
ca394fc8ab
Merge pull request #3182 from GNURub/feature/autobind
Add method to set the data depending on the accepted
2018-07-20 15:05:28 +08:00
astaxie
9c9ba0129f
Merge pull request #3226 from jianjianzhu/master
Fix the wrong status code in prod
2018-07-20 14:53:08 +08:00
astaxie
b61c91d93d remove unnecessary conversion 2018-07-20 14:47:11 +08:00
astaxie
f15732798f
Merge pull request #3239 from wilhelmguo/develop
add session redis IdleTimeout config
2018-07-20 14:44:07 +08:00
astaxie
efbe655d6a
Merge pull request #3245 from 0x0400/patch-1
fix typo
2018-07-20 14:43:38 +08:00
astaxie
27ced1d9c3
Merge pull request #3247 from mohan2808/develop
send ErrNoRows if the query returns zero rows ... in method orm_query…
2018-07-20 14:34:23 +08:00
astaxie
8f6bce3b87 fix test case 2018-07-20 14:26:43 +08:00
astaxie
be75f93d43 add miss dep 2018-07-20 12:14:27 +08:00
astaxie
541fb181fe Merge branch 'master' into develop 2018-07-20 12:00:53 +08:00
mohan2808
293b54192f send ErrNoRows if the query returns zero rows ... in method orm_queryset.All() 2018-07-19 18:51:16 +05:30
Xingang Zhang
0e0718d110
fix typo
hasReuired --> hasRequired
2018-07-17 23:32:11 +08:00
guoshaowei
6fec0a7831 add session redis IdleTimeout config 2018-07-12 10:48:50 +08:00
astaxie
654ebebe3c
Merge pull request #3217 from jinxjinxagain/develop
fix: When multiply comment routers on one func
2018-07-08 16:13:21 +08:00
astaxie
08c3ca642e
Merge pull request #3230 from Colstuwjx/fix/correct-httplib-maxidleconnection-default-value
Fix: correct MaxIdleConnsPerHost value to net/http default 100.
2018-07-08 16:11:35 +08:00
Colstuwjx
b3c46a87ac Fix: correct MaxIdleConnsPerHost value to net/http default 100. 2018-07-05 19:15:42 +08:00
zhujianjian
464d080518 fix httpcode in prod 2018-07-02 11:21:06 +08:00
jinxjinxagain
227c04c9e6 fix: When multiply comment routers on one func, only generates the last one controller 2018-06-28 15:54:17 +08:00
astaxie
e5d68aceed
Merge pull request #3185 from kaka89/master
Fix defaut value bug, and add config for maxfiles
2018-06-23 22:54:35 +08:00
astaxie
67d9241abc
Merge pull request #3171 from whomm/master
debug stringsToJSON
2018-06-23 22:50:11 +08:00
astaxie
110dbcb31f
Merge pull request #3208 from hurisheng/qs_forupdate
add 'FOR UPDATE' support for querySet
2018-06-23 22:49:01 +08:00
astaxie
740bf72f0c
Merge pull request #3202 from openset/develop
Update: Htmlquote Htmlunquote
2018-06-23 22:43:53 +08:00
astaxie
6b3b8607a0
Merge branch 'develop' into develop 2018-06-23 22:43:45 +08:00
astaxie
b21c59ee70
Merge pull request #3206 from whilei/gofmt-2018-Jun-17-00-39
gofmt
2018-06-23 22:38:07 +08:00
hurisheng
fc2c96a177 add 'FOR UPDATE' support for querySet 2018-06-23 22:25:05 +08:00
ia
87ba3f3cd3 all: gofmt
Run standard gofmt command on project root.

- go version go1.10.3 darwin/amd64

Signed-off-by: ia <isaac.ardis@gmail.com>
2018-06-17 00:47:51 +02:00
Openset
b80b7b06fc Update: Redundant semicolon disableEscapeHTML 2018-06-14 11:55:07 +08:00
Openset
ad6c97ec1b Update: Htmlquote Htmlunquote 2018-06-13 15:43:01 +08:00
astaxie
d3d97de312
Merge pull request #3200 from openset/master
Update: use PathEscape replace QueryEscape
2018-06-12 22:45:14 +08:00
Sandy
bf915c3280
Update: use PathEscape replace QueryEscape
If filename contain space(" "), QueryEscape use "+" instead.
2018-06-12 16:15:20 +08:00
astaxie
19c5cd130d
Merge pull request #3190 from NSObjects/develop
add field comment on create table
2018-06-07 11:06:23 +08:00
lintao
1df2662924 add field comment on create table 2018-06-06 12:33:28 +08:00
umasuo
f979050a45
Fix defaut value bug, and add default maxfiles
1. add default value for maxlines(100000), maxsize(1 << 28)
2. add maxfiles for configure, just like `maxlines` & maxsize
2018-06-03 23:08:03 +08:00
Ruben Cid
45b68d444d Add method to set the data depending on the accepted 2018-06-01 19:11:01 +02:00
Ruben Cid
732f79e758 Add dep travis 2018-05-31 14:52:47 +02:00
Ruben Cid
4e954e32b8 Test YAML 2018-05-31 13:48:24 +02:00
Ruben Cid
92e81ccf50 Merge branch 'develop' into feature/YAML 2018-05-31 13:35:44 +02:00
Ruben Cid
91f2005067 Test YAML 2018-05-31 13:35:23 +02:00
Ruben Cid
7c80bf6f9d Add YAML 2018-05-30 16:06:40 +02:00
astaxie
cc2c98c112 update travis 2018-05-30 22:01:59 +08:00
astaxie
c3c0adbf55
Merge pull request #3175 from mo0feng/master
Create redis_cluster.go
2018-05-28 16:48:06 +08:00
jz
04c305f273
fix use it comments
fix  use it comments
2018-05-24 15:14:56 +08:00
jz
8c8cf46b55
Create redis_cluster.go
super redis cluster
2018-05-23 17:30:13 +08:00
whomm
e96ae0c24a debug stringsToJSON
json char: \u four-hex-digits number(http://json.org/)
2018-05-21 15:18:18 +08:00
Amit Yadav
98a3cda260 Fix Unexpected EOF bug in staticfile 2018-05-07 13:51:05 +05:30
Wang-Kai
1fd7fa5df7 make example runable 2018-05-03 22:04:49 +08:00
astaxie
3d3f2ed4c5
Merge pull request #3127 from kaka89/master
Refactor yaml config for support multilevel
2018-05-03 14:07:59 +08:00
Wang-Kai
0f73050567 add code style for logs README 2018-05-03 12:05:59 +08:00
astaxie
a40899e6be
Merge pull request #3145 from gadelkareem/develop
Allow log prefix
2018-05-03 11:27:50 +08:00
Waleed Gadelkareem
a9a15e2c54 Allow log prefix 2018-05-02 00:24:09 +02:00
Waleed Gadelkareem
896c258e44 Log redirects and abort after redirect 2018-04-30 17:48:01 +02:00
Amit Ashkenazi
6df42d63e2 Fix response http code 2018-04-29 15:12:32 +03:00
Waleed Gadelkareem
33bf80b052 Merge branch 'pr/3141' into patch-2 2018-04-28 20:07:23 +02:00
Waleed Gadelkareem
d5c1c0e9a4 log errors in access log and make static request logging optional 2018-04-28 20:03:39 +02:00
Waleed Gadelkareem
8e61a6a6de
Allow access log regardless of the log level 2018-04-28 17:15:19 +02:00
umasuo
ccaa2dd9e0
Update yaml.go
delete white line.
2018-04-20 19:44:22 +08:00
astaxie
507ea757d7
Merge pull request #3039 from cloudzhou/patch-1
execElem.FieldByName as local variable
2018-04-20 19:41:07 +08:00
astaxie
9d526dfd50
Merge pull request #3100 from godcong/master
change github.com/garyburd/redigo to newest branch github.com/gomodul…
2018-04-20 19:40:30 +08:00
umasuo
ba89253e4a
Update yaml.go
add support for multilevel yaml config
2018-04-20 19:40:06 +08:00
astaxie
0d6f190e72
Merge pull request #3107 from sergeylanzman/patch-1
Update .travis.yml golang 1.10
2018-04-20 19:33:50 +08:00
astaxie
91b9a65db0
Merge pull request #3109 from Jeff885/Jeff885-patch-1
When log maxSize set big int,FileWrite Init fail
2018-04-20 19:33:33 +08:00
astaxie
e96a5fb3ca
Merge pull request #3115 from m4grio/minor-typo
Amend a very minor typo in a variable name
2018-04-20 19:26:42 +08:00
astaxie
f5f70f386d
Merge pull request #3126 from aruhi/master
In dev mode, template parse error cause program lock
2018-04-20 19:26:24 +08:00
astaxie
242efcf7fa
Merge pull request #3103 from qshuai/master
fix typo
2018-04-20 19:26:00 +08:00
aruhi
51cc6fc257
Update template.go 2018-04-20 19:42:50 +09:00
Mario Álvarez
5fb29cb772
Amend a very minor typo in a variable name 2018-04-10 12:19:50 +08:00
MinJie Gu
2da894d4a7
When log maxSize set big int,FileWrite Init fail
example:
beego.SetLogger("multifile", {"filename":"logs/liverelay.log","separate":[ "emergency", "error", "info", "debug"],"maxsize":250000000}).

json: cannot unmarshal number 2.5e+08 into Go value of type int

The err should return and show the developer.
2018-04-06 00:50:35 +08:00
Sergey Lanzman
2623b15ce0
Update .travis.yml 2018-04-05 16:30:08 +03:00
chenkaihui
6db9ad7002 auto create log dir 2018-04-04 15:59:52 +08:00
qshuai
889408136b fix typo 2018-03-28 00:26:06 +08:00
godcong
886fefe738 change github.com/garyburd/redigo to newest branch github.com/gomodule/redigo 2018-03-26 16:59:01 +08:00
astaxie
768406f134
Merge pull request #3076 from gadelkareem/patch-1
Set default Beego RunMode to production
2018-03-11 16:26:00 +08:00
astaxie
075e63b2bd
Merge pull request #2999 from moririnson/fix_unable_to_add_column
fix the issue #2998
2018-03-11 16:18:50 +08:00
astaxie
0057c08a90
Merge pull request #3085 from WUMUXIAN/swagger
Swagger: Allow example values with different types, allow example for enum.
2018-03-11 10:48:48 +08:00
WUMUXIAN
09b073356d Swagger:
1. Allow example value to be given based on the field type, previously it's a string.
2. Allow to give example values for Enum values.

This is for the beego/bee pull request to work well.
2018-03-10 17:15:24 +08:00
Waleed Gadelkareem
3c9ed48630
Set default Beego RunMode to production 2018-03-02 18:23:20 +01:00
astaxie
65d8b4f544
Merge pull request #3064 from takeo-lvgs/dev
fix the issue #3063
2018-02-22 17:22:39 +08:00
astaxie
6d18d4dcdd
Merge pull request #3066 from takeo-lvgs/fix_3065
fix the issue #3065
2018-02-22 17:16:38 +08:00
takeo-lvgs
21fe2d519e fix the issue #3065 2018-02-20 17:40:18 +09:00
takeo-lvgs
9a7554fa01 fix the issue #3063 2018-02-20 11:39:29 +09:00
astaxie
37d1c13603
Merge pull request #3046 from aspacca/master
Handle pointer validation
2018-02-02 18:57:13 +08:00
Andrea Spacca
5ed112e946 added CanSkipAlso 2018-02-02 10:22:43 +01:00
Andrea Spacca
453f112094 added more test case 2018-02-01 18:31:04 +01:00
Andrea Spacca
faa3341603 Fix after test failure 2018-01-28 18:19:27 +01:00
Andrea Spacca
ee9cf05796 Handle pointer validation 2018-01-28 17:40:05 +01:00
cloudzhou
6de538b136
execElem.FieldByName as local variable
execElem.FieldByName(fieldType.Name) as local variable
2018-01-25 17:52:09 +08:00
陈培远
47c1072b78 do html escape before display path, avoid xss 2018-01-08 19:35:53 +08:00
astaxie
e81f1e53bf
Merge pull request #3017 from Medicean/develop
Update: Fix migration generate SQL
2018-01-05 00:10:16 +08:00
Medicean
cf92d2c6ef Update: Fix migration generate SQL 2018-01-04 10:42:39 +08:00
astaxie
0507076c3f
Merge pull request #3004 from pcallewaert/develop
redis cache: make MaxIdle configurable
2017-12-30 13:54:11 +08:00
Pieter Callewaert
59fd3952b7 bug: restore the default value 2017-12-26 11:48:34 +01:00
Pieter Callewaert
7fd80e6aa1 feat(redis.go): make MaxIdle configurable 2017-12-26 11:48:08 +01:00
smori
24fa6189b5 fix the issue #2998 2017-12-23 16:41:56 +09:00
dennismao
0bde9cbd91 fix the issue #2995 2017-12-22 16:21:23 +08:00
astaxie
122414d789
Merge pull request #2992 from priteshgudge/develop
Update Documentation in Output.go
2017-12-21 17:08:10 +08:00
Pritesh Gudge
aac69674ad
Update Documentation in Output.go
Fix Documentation for HTTP status codes descriptions.
2017-12-21 13:50:28 +05:30
chenxiaonan01
1a42154c64 add file test 2017-12-20 17:54:40 +08:00
chenxiaonan01
e81cca304b add file test 2017-12-20 16:19:58 +08:00
chenxiaonan01
07aa97aa9a add hourly rotate file.go 2017-12-20 15:56:36 +08:00
Terry Ding
94fba0b2aa fix orm fields SetRaw function error judge problem 2017-12-20 14:53:00 +08:00
astaxie
80aa47f605
Merge pull request #2976 from szyhf/develop
Fix #2975
2017-12-19 23:34:17 +08:00
astaxie
f16688817a
Merge pull request #2978 from BorisBorshevsky/fix_reflection_bug
fix bug #2972
2017-12-18 19:18:59 +08:00
TankTheFrank
2670a86005 fix #2979 2017-12-14 17:55:08 +02:00
BorisBorshevsky
0e369e6df8 fix bug 2017-12-13 15:27:32 +02:00
Back Yu
84443b9c05
Fix #2975
修复AccessLog输出会多换一行的bug
2017-12-12 12:21:55 +08:00
astaxie
33be6803a3
Merge pull request #2970 from gcy3y/master
update log.go add GetLevel Function to Log
2017-12-10 20:26:46 +08:00
astaxie
aef2f1c66e
Merge pull request #2971 from PureWhiteWu/fix_typo
fix a typo
2017-12-10 18:47:54 +08:00
Pure White
619cd2d908
fix a typo 2017-12-08 23:01:21 +08:00
GuoChunYang
4613acd88e
update log.go add GetLevel Function to Log 2017-12-08 15:35:12 +08:00
astaxie
bf5c5626ab
Merge pull request #2943 from astaxie/develop
1.9.2
2017-12-06 23:37:36 +08:00
astaxie
0fbbc67c3d
Merge pull request #2961 from zhlicen/master
Add lock while releasing session
2017-12-06 14:44:25 +08:00
astaxie
3e1916ec3c
Merge pull request #2953 from szyhf/develop
Proposal to #2952
2017-12-06 14:43:12 +08:00
astaxie
b068a676dd
Merge pull request #2950 from huhaocc/change_httpmethod_type
Change the type of HTTPMETHOD
2017-12-06 14:42:35 +08:00
HANG ZHOU
ed73bdcfab
Add lock while releasing session
Solve the problem of SessionRead failure while ReleaseSession is in progress
2017-12-05 16:18:56 +08:00
astaxie
ae94b705ea
Merge pull request #2954 from axetroy/master
test: Improve test case for utils/safemap, make it 100% cover
2017-12-01 23:33:46 +08:00
axetroy
08fb921053 test: Improve test case for utils/safemap, make it 100% cover 2017-12-01 01:04:15 +08:00
Back Yu
e67e57f8fb orm: 修复logic enum因为type enum改变而产生的位错位。 2017-11-30 20:26:34 +08:00
Back Yu
b30969704a Proposal to #2952 2017-11-30 18:12:49 +08:00
hao.hu
646acc423e Change HTTPMETHOD type 2017-11-30 01:43:50 +08:00
astaxie
c3a81a23f9 beego 1.9.2 2017-11-27 15:52:31 +08:00
astaxie
103dd22151 remove mysq travis 2017-11-27 15:42:18 +08:00
astaxie
ec6cb43711 fix ci failed 2017-11-27 14:07:05 +08:00
astaxie
84cb9a5986 update to go1.9.2 2017-11-26 14:35:37 +08:00
astaxie
9b8bc2aef7
Merge pull request #2941 from BorisBorshevsky/report-card
add report card to readme.md
2017-11-26 14:32:57 +08:00
astaxie
9710d9e961
Merge pull request #2940 from BorisBorshevsky/golint
fix golint comments
2017-11-26 14:32:40 +08:00
BorisBorshevsky
58bb49a78c add report card to readme.md 2017-11-25 19:23:46 +02:00
BorisBorshevsky
df37739c7d fix golint comments 2017-11-25 19:18:37 +02:00
astaxie
a5dd5d161d
Merge pull request #2659 from ansiz/master
to close issue #1899(redis cache doubt)
2017-11-19 11:13:42 +08:00
astaxie
6827107177
Merge pull request #2706 from fat4lix/bugfix
Fix run controller if it set by RumController and RunMethod in Filterfunc
2017-11-19 11:12:48 +08:00
astaxie
a30a89e57e
Merge pull request #2849 from iclinux/grace-patch
Make parent process exit gracefully.
2017-11-19 11:09:13 +08:00
astaxie
d352e4abcb
Merge pull request #2852 from Radar8/master
validation: fix ErrorMap, added AddError(key, message)
2017-11-19 11:08:31 +08:00
astaxie
a948d4c1e1 set default to apache format 2017-11-19 11:07:57 +08:00
astaxie
b7eb3963f5
Merge pull request #2863 from gadelkareem/develop
Add JSON or Apache access log formatting option to config:  AccessLogsFormat = JSON_FORMAT or APACHE_FORMAT  ref #2738
2017-11-19 11:05:12 +08:00
astaxie
f7afb3cb75
Merge pull request #2878 from silviucm/master
Add the ability to unregister fixed routes
2017-11-19 10:41:40 +08:00
astaxie
348bf51a42
Merge pull request #2914 from AbelZhou/master
Add sys env feature
2017-11-19 10:41:22 +08:00
astaxie
dfea2cc5f3
Merge pull request #2928 from ilylia/develop
add Enum field to Schema
2017-11-19 10:27:11 +08:00
astaxie
532eab8e1d
Merge pull request #2932 from lotus-wu/Branch_v1.9.0
1.Add Mutual HTTPS  Option!
2017-11-19 10:26:59 +08:00
lotus
3872382a4b 1.Add Mutual HTTPS Option! 2017-11-15 22:42:30 +08:00
ilylia
4018693fbd add Enum field to Schema 2017-11-13 14:36:08 +08:00
astaxie
3b829504f6
Merge pull request #2920 from chenpeiyuan/develop
avoid unnecessary read of large log file
2017-11-07 09:35:09 -06:00
陈培远
80fa51468c avoid unnecessary read of large log file
If w.MaxLines is not set, there is no need to calc large log file’s lines. It may takes more than 10mins to calc a 10G file.
2017-11-07 22:58:39 +08:00
Abel
3504d2a4da Add host env feature. 2017-10-31 19:19:14 +08:00
Abel
229d8b9530 Add host env feature. 2017-10-30 13:54:36 +08:00
Silviu Capota-Mera
9536d460d0
Create test file for the route unregistering functionality 2017-10-28 14:49:41 -04:00
astaxie
e211e4839c Merge pull request #2906 from mlgd/patch-1
Update for MySQL timezone detection bug
2017-10-27 09:47:09 -05:00
mlgd
3332dbe595 Update for MySQL timezone detection bug
Use "DefaultTimeLoc" for "al.TZ" default value
Don't set TZ on alias when t.Location() is empty

You can set your MySQL server timezone on main.go init function.
Example :
orm.DefaultTimeLoc, _ = time.LoadLocation("Europe/Paris")
2017-10-26 14:32:42 +02:00
Abel
b9c8c08c03 Add host env feature. 2017-10-26 19:25:05 +08:00
astaxie
663f22d849 Merge pull request #2893 from melotusme/master
Typo fixed
2017-10-23 06:48:46 -05:00
astaxie
fbaa4d1233 Merge pull request #2898 from skOak/swagger
remove omitempty for swagger.Response.Description, because it's Required according to Swagger2.0 Spec
2017-10-23 06:48:22 -05:00
astaxie
7dc8991140 Merge pull request #2894 from skOak/develop
add custom middleware options for beego.Run()
2017-10-23 06:48:03 -05:00
hemin
0ce70b8c99 remove omitempty for swagger.Response.Description, because it's Required according to Swagger2.0 Spec 2017-10-18 22:34:24 +08:00
astaxie
b169ea4b63 Merge pull request #2896 from tinycedar/master
misc: fix typos
2017-10-17 21:22:27 +08:00
Daniel Lin
72ec4df679 Merge branch 'master' into master 2017-10-17 04:30:59 -05:00
hzlinqien
b91263a254 misc: fix typos 2017-10-17 17:27:03 +08:00
hemin
e91afb1938 add custom middleware options for beego.Run() 2017-10-16 14:55:08 +08:00
zhirong
74eb613919 Typo fixed 2017-10-16 00:06:20 +08:00
astaxie
32d4310861 Merge pull request #2886 from hurisheng/patch-1
add XMLBody method for httplib
2017-10-14 07:57:02 -05:00
astaxie
c56704f3fd Merge branch 'master' into develop 2017-10-14 17:53:40 +08:00
astaxie
c5118e9535 Merge pull request #2889 from lidaobing/fix_typo
fix typo
2017-10-14 03:28:56 -05:00
LI Daobing
9b57566963 fix typo 2017-10-11 14:35:31 +08:00
Silviu Capota-Mera
8d59e7afd1 for the root path, all methods must be covered
use continue instead of return
2017-10-07 13:16:36 -04:00
Silviu Capota-Mera
fd733f76f0 simplify replacement of the base (root) tree 2017-10-07 12:14:28 -04:00
Hu Risheng
37d4bb3df5 add XMLBody method for httplib 2017-10-05 14:34:52 -05:00
Silviu Capota-Mera
5697c6d7cc Remove redundant return to pass gosimple Travis check 2017-09-25 23:17:57 -04:00
Silviu Capota-Mera
51a6162363 Update app.go 2017-09-25 21:45:42 -04:00
Silviu Capota-Mera
5a12b3d020 Add the ability to unregister fixed routes
Certain web application inherit most of the routes from a base application by using the underscore import 
(e.g. import _ "myoldapp.com/routers").
The new application might want to only overwrite certain pages, such as "/about" or "/faq"

The proposed new UnregisterFixedRoute method allows unregistering of the specified paths.
 Usage (replace "GET" with "*" for all methods):
  beego.UnregisterFixedRoute("/yourpreviouspath", "GET")
  beego.Router("/yourpreviouspath", yourControllerAddress, "get:GetNewPage")
The children paths are left intact.
For example, /yourpreviouspath/oldchildsubpath should still continue to function in legacy mode.
2017-09-25 20:52:19 -04:00
Waleed Gadelkareem
bebd2c469d Remove typo 2017-09-13 22:15:40 +02:00
Waleed Gadelkareem
d15e66a4ff check if SetEscapeHTML exists instead of checking Go version 2017-09-13 22:14:41 +02:00
Waleed Gadelkareem
c04d43695c fix dependency go-version for travis 2017-09-13 03:16:33 +02:00
Waleed Gadelkareem
d813334a24 Merge branch 'develop' of github.com:gadelkareem/beego into develop 2017-09-13 03:10:08 +02:00
Waleed Gadelkareem
9fef2f2eb4 Do not escape html if Golang version < 1.7 2017-09-13 03:09:53 +02:00
Waleed Gadelkareem
0c746f4547 Merge branch 'master' into develop 2017-09-13 02:16:50 +02:00
Waleed Gadelkareem
f5c8b1c6ac Merge branch 'master' of github.com:gadelkareem/beego 2017-09-13 02:05:15 +02:00
Waleed Gadelkareem
4921014c64 Add JSON or Apache access log formatting option to config: AccessLogsFormat = JSON_FORMAT or APACHE_FORMAT ref #2738 2017-09-13 02:03:46 +02:00
astaxie
520753415f Merge pull request #2846 from hikenote/master
return template build error rather than log error
2017-09-09 06:42:02 +08:00
astaxie
3162da131d Merge pull request #2858 from astaxie/revert-2854-master
Revert "should use time.Since instead of time.Now().Sub"
2017-09-09 06:29:59 +08:00
astaxie
a7354d2d08 Revert "should use time.Since instead of time.Now().Sub" 2017-09-09 06:29:38 +08:00
astaxie
07a9a2d0f3 Merge pull request #2854 from wgliang/master
should use time.Since instead of time.Now().Sub
2017-09-09 06:29:31 +08:00
wangguoliang
c8c25549e7 should use time.Since instead of time.Now().Sub
Signed-off-by: wgliang <liangcszzu@163.com>
2017-09-07 19:01:34 +08:00
Radar8
6641a436a2 validation: fix ErrorMap, added func AddError(key, message) 2017-09-06 16:49:21 +08:00
iclinux
1dd50fb65f Make parent process exit gracefully.
With beego.BConfig.Listen.Graceful  enabled, when received SIGHUP, we'll fork a child process.
But the parent process still have jobs to finish, So we can't kill the parent process directly.
2017-09-05 11:53:42 +08:00
zhufanmao
4bc4f77c29 return template build error 2017-09-02 17:55:26 +08:00
zhufanmao
ef36ecd376 avoid some proxy not support select command 2017-08-31 20:26:32 +08:00
astaxie
c6cef853c7 Merge pull request #2813 from mlgd/develop
Add IPV6 compatibility
2017-08-23 16:54:59 +08:00
astaxie
33ad8d5db4 Merge pull request #2815 from wisererik/patch-1
Fix the quick start section of the orm/README.md
2017-08-23 16:53:41 +08:00
astaxie
33e6d57754 Merge pull request #2820 from crazcalm/doc_error
fixed mispelled word
2017-08-22 23:18:31 +08:00
Marcus Willock
afa57ca1f2 fixed mispelled word 2017-08-20 23:32:11 +08:00
Erik
510dd02a06 Fix the quick start section of the orm/README.md
Increase the init method by adding the `RunSyncdb` method to resolve the problem that the table is not created.
2017-08-11 11:34:18 +08:00
mlgd
166e88c103 Update input.go 2017-08-09 21:05:06 +02:00
mlgd
51b6adeb24 Add IPV6 compatibility 2017-08-09 10:23:03 +02:00
astaxie
51c19c374a Merge pull request #2801 from nightlyone/patch-1
fix bad error code in seesion handling
2017-08-06 22:29:05 +08:00
astaxie
b23452dc3f Merge pull request #2805 from ninjacn/master
comment edit
2017-08-06 22:28:36 +08:00
astaxie
f61038e6bd Merge pull request #2803 from iamzhout/log_add_milliseconds
add millisecond to timestamp in log output
2017-08-06 22:28:19 +08:00
Tao Zhou
b9117e2ff1 add millisecond to timestamp in log output 2017-08-04 00:11:59 +08:00
姚鹏鸣
5a7a3da909 comment edit 2017-08-03 19:15:32 +08:00
Ingo Oeser
3f4502990a fix bad error code
By providing a unique error code instead of a format specifier without using an error formatting function.
2017-08-03 01:52:24 +02:00
astaxie
e14113aa0e Merge pull request #2656 from BorisBorshevsky/develop
Allow injecting dependencies to controllers
2017-07-30 23:36:52 +08:00
astaxie
d96289a81b Merge pull request #2771 from astaxie/develop
v1.9.0
2017-07-19 00:56:48 +08:00
astaxie
4fc95b0d69 gofmt and golint 2017-07-19 00:52:27 +08:00
astaxie
aa3d6c5363 fix the gosimple 2017-07-19 00:37:42 +08:00
astaxie
5ac0cb929c v1.9.0 2017-07-18 23:58:22 +08:00
astaxie
b27ab53017 fix issue for runMethod and runRouter from context 2017-07-18 23:41:50 +08:00
astaxie
1aba294405 Merge pull request #2740 from xlwcom/master
fix the bugs in the "ParseBool" function in the file of config.go
2017-07-18 13:39:45 +08:00
astaxie
657e55ed59 Merge pull request #2692 from jerson/master
added statusCode and pattern to FilterMonitorFunc
2017-07-17 11:06:09 +08:00
astaxie
621c25396e Merge pull request #2766 from yangsf5/master
sort ControllerComments
2017-07-17 11:02:28 +08:00
astaxie
715ba918f0 Merge pull request #2744 from gnanakeethan/feature/database-migration
[Proposal] Database Migrations;
2017-07-17 10:54:44 +08:00
Gnanakeethan Balasubramaniam
8bb0a70847
Update: Fix in SQL Generation
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-16 08:48:44 +05:30
Gnanakeethan Balasubramaniam
94e79eddcf
Update: removing remnant of revert commit ( a call to function
m.DDLSpec() )

Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-16 08:37:27 +05:30
Gnanakeethan Balasubramaniam
749a4028b4
Revert "Update: removing the need to call DDLSpec in the migration file"
The odds of getting this perfectly up is not good.

This reverts commit d58ad2ee3697ff0ccda83d020abc7080d99f0a5e.
2017-07-16 08:11:10 +05:30
Gnanakeethan Balasubramaniam
fc55c2b57c
Update: missed to call DDLSpec in Down migration
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-16 07:30:53 +05:30
Gnanakeethan Balasubramaniam
d58ad2ee36
Update: removing the need to call DDLSpec in the migration file
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-16 07:24:58 +05:30
Gnanakeethan Balasubramaniam
cb38ab4f85
Update: fixing a SQL generation code
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-16 07:10:09 +05:30
shanfeng.yang
fc86f6422d sort ControllerComments 2017-07-15 17:26:20 +08:00
Gnanakeethan Balasubramaniam
d453242e48
Update: moving package to bottom
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-14 14:42:56 +05:30
Gnanakeethan Balasubramaniam
7c2ec075a4
Update: fixing some methods and adding documentation
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-13 21:03:30 +05:30
Gerson Alexander Pardo Gamez
c903de41e4 updated sample for FilterMonitorFunc
added pattern to sample
2017-07-12 09:51:37 -05:00
astaxie
e8c8366308 Merge pull request #2754 from imiskolee/develop
supported gzip for req.Header has `Content-Encoding: gzip`
2017-07-12 19:57:29 +08:00
astaxie
4901567bba Merge pull request #2749 from satng/patch-4
oracle插入占位符
2017-07-12 19:49:32 +08:00
MiskoLee
29bcd31b27 supported gzip for req.Header has Content-Encoding: gzip 2017-07-10 21:27:54 +08:00
satng
83a563c0ab oracle插入占位符 2017-07-09 12:25:51 +08:00
Gnanakeethan Balasubramaniam
e888fee4e0
Update: Foreign Key & Comments
Summary: Foreign Key functions are now available

Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-06 20:26:37 +05:30
Gnanakeethan Balasubramaniam
c1ba11f531
Fixing typo
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-06 14:58:40 +05:30
Gnanakeethan Balasubramaniam
ed558a0e70
Fix: typo due to find and replace migration renamed to m
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-06 07:45:07 +05:30
Gnanakeethan Balasubramaniam
6b9c3f4824
[Proposal] Database Migrations;
Summary: The database migrations now can be created using the methods on
the migration struct. it does not break any existing migration features.
it upgrades the migration struct and adds few more struct types so that
the migrations can be efficiently generated for create, alter, reverse,
drop.

Current Features:
* Supports creation of columns
   * `m.NewCol("name").SetDataType("VARCHAR(10)").SetNullable("true")`
   * **NOTE** `SetNullable` & `SetDefault` methods should not be called on
   same column for consistency
* Supports addition of primary keys
   * `m.PriCol("id").SetDataType("INT(10)").SetNullable("true")`
   * **NOTE** `setAuto(true)` can be only called on Primary keys
* Supports addition of unique keys
   * `m.UniCol("unique_index","column_name").SetDataType("VARCHAR(23)").SetNullable("true")`
   * **NOTE** `UniCol` can be called again with the same index name to
   add column to the index
* Supports rename of columns
   * `m.RenameColumn("from_name","to_name")`
   * Allows standard column methods and methods such that, `SetOldDefault` allows
   reversibility of renames

* TODO:
   * ForeignKey

Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-06 07:44:48 +05:30
astaxie
7ec819deed fix #2725 big form 2017-07-04 21:16:59 +08:00
astaxie
4cfb3678f8 Merge pull request #2741 from miraclesu/validation
validation: support required option for some struct tag valids
2017-07-04 15:49:36 +08:00
xlwcom
3c17e2a7e6 remove the comments 2017-07-04 11:03:49 +08:00
miraclesu
e72b02b7cc validation: support required option for some struct tag valids 2017-07-03 16:26:23 +08:00
astaxie
82586c70e9 Merge pull request #2683 from jialijelly/master
Provide permission to access old files to everyone
2017-07-03 11:23:49 +08:00
astaxie
cb86bcc9e8 Merge pull request #2728 from miraclesu/validation
validation: support int64 int32 int16 and int8 type on 64-bit platform
2017-07-01 15:35:48 +08:00
xlwcom
234708062a fix the bug in the "ParseBool" function in the file of config.go 2017-06-29 13:32:40 +08:00
miraclesu
6e34f43721 Fix break API change
support int64 on 64-bit platform
2017-06-28 16:56:37 +08:00
Jia Li Ong
3249ec8ebf Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-27 10:49:10 +08:00
Jia Li Ong
31b2b21dbc Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-27 10:48:52 +08:00
Jia Li Ong
d0c1936922 Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-22 19:18:49 +08:00
Jia Li Ong
338a23a12b Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-22 19:18:34 +08:00
Jia Li Ong
932def1ed2 Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-22 18:55:37 +08:00
Jia Li Ong
16b5a11484 Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-22 18:55:25 +08:00
Jia Li Ong
547fbce86c Merge branch 'master' of https://github.com/jialijelly/beego 2017-06-22 18:53:29 +08:00
Jia Li Ong
5a2eea07cb Provide permission to access old log files to everyone 2017-06-22 18:51:52 +08:00
miraclesu
2231841d74 validation: support int64 int32 int16 and int8 type 2017-06-21 14:13:30 +08:00
astaxie
805a674825 Merge pull request #2712 from eyalpost/develop
incorrect error rendering (wrong status)
2017-06-16 13:34:28 +08:00
astaxie
f2925978f1 Merge pull request #2717 from huwenbo/master
fix panic sync: negative WaitGroup counter
2017-06-16 13:26:36 +08:00
astaxie
fe3a224a23 Merge pull request #2724 from JessonChan/develop
AddAPPStartHook func modify
2017-06-16 08:20:45 +08:00
astaxie
2754edc849 Merge pull request #2726 from moqiancong/develop
fix cache/memory fatal error: concurrent map iteration and map write
2017-06-16 08:20:03 +08:00
moqiancong
79f60274a0 fix cache/memory fatal error: concurrent map iteration and map write 2017-06-16 01:26:55 +08:00
JessonChan
a87c1c5e8e AddAPPStartHook func modify 2017-06-15 17:36:37 +08:00
huwenbo
2b00b7d66d fix panic: sync: negative WaitGroup counter 2017-06-13 20:15:43 +08:00
huwenbo
3d9286f089 fix panic: sync: negative WaitGroup counter 2017-06-13 15:34:57 +08:00
huwenbo
55e6c15073 fix panic: sync: negative WaitGroup counter 2017-06-13 15:19:51 +08:00
eyalpost
8b504e7d51 incorrect error rendering (wrong status) 2017-06-12 21:05:40 +03:00
Илья Маслов
47ef2b343e Fix run controller if it set by RumController and RunMethod in Filterfunc 2017-06-09 15:53:03 +03:00
Илья Маслов
80dcdb8645 Fix run controller if it set by RumController and RunMethod in FilterFunc 2017-06-09 15:27:26 +03:00
astaxie
d1c3bd8416 Merge pull request #2701 from eyalpost/develop
correctly handle multiple params with same type
2017-06-09 15:33:37 +08:00
eyalpost
0240e182c6 correctly handle multiple params with same type 2017-06-09 10:15:36 +03:00
Gerson Alexander Pardo Gamez
7f2e3feb3c added pattern to FilterMonitorFunc 2017-06-05 18:21:31 -05:00
Gerson Alexander Pardo Gamez
d15dd2795c added statusCode in FilterMonitorFunc 2017-06-03 15:24:45 -05:00
Jia Li Ong
0ea34fff27 Provide permission to access old log files to everyone 2017-06-02 10:56:55 +08:00
xhzhang
4e8f212069 refactor: #1899 redis cache module refactor
redis cache module refactor, to view the discussion:

  https://github.com/astaxie/beego/issues/1899
2017-05-20 19:56:38 +08:00
xhzhang
eb71d0ea7f Merge remote-tracking branch 'upstream/master' 2017-05-20 19:39:24 +08:00
BorisBorshevsky
b24ddb953c merge from upstram + resolve conflicts 2017-05-20 02:42:00 +03:00
BorisBorshevsky
12f8fbe37f Allow injecting dependencies to controllers 2017-05-20 02:06:28 +03:00
astaxie
5e8312bc23 Merge pull request #2654 from casbin/master
Fix the new repo address for casbin.
2017-05-19 23:34:58 +08:00
Yang Luo
88d07058a5 Fix the new repo address for casbin. 2017-05-19 22:19:31 +08:00
astaxie
cab8458c1c Merge pull request #2651 from astaxie/develop
v1.8.3
2017-05-19 21:19:18 +08:00
astaxie
f0b95c552b Merge pull request #2315 from sch00lb0y/master
issue no:#2261 fix for xsrf panic error
2017-05-19 18:50:56 +08:00
பாலாஜி
ce677202e5 issue no:#2261 fix for xsrf panic error 2017-05-19 14:02:14 +05:30
astaxie
720c323e20 Merge pull request #2652 from gouyang/gouyang/dev
Support timeformat "2006-01-02T15:04:05"
2017-05-19 09:48:35 +08:00
Guohua Ouyang
47e351e11d Support timeformat "2006-01-02T15:04:05"
Fixes #2649

Signed-off-by: Guohua Ouyang <guohuaouyang@gmail.com>
2017-05-19 09:22:27 +08:00
astaxie
248beab557 v1.8.3 2017-05-18 22:55:10 +08:00
astaxie
388a5610fa Merge pull request #2365 from chesedo/RequiredValidationCatchSpaces
[WIP]Have Required validator trim strings to fix #2361
2017-05-18 22:44:15 +08:00
astaxie
41498758fe Merge pull request #2620 from hsluoyz/authz
Add an authorization plugin that supports ACL, RBAC based on casbin.
2017-05-18 18:18:12 +08:00
astaxie
655484b4df Merge pull request #2586 from eyalpost/develop
Automatic Parameter Router
2017-05-18 18:14:49 +08:00
Eyal Post
11b4bf8aaa move to context 2017-05-18 10:38:12 +03:00
Eyal Post
2513bcf584 remove Redirect to avoid confusion 2017-05-18 10:32:51 +03:00
Eyal Post
3e51823c0f move response 2017-05-18 09:05:49 +03:00
Eyal Post
e32a18203b fix gosimple 2017-05-17 21:27:32 +03:00
Eyal Post
ee1d8bc30e fix gosimple 2017-05-17 20:50:41 +03:00
Eyal Post
828cbbdf5d Refactor a bit to consolidate packages 2017-05-17 20:38:59 +03:00
Eyal Post
d54cd4fa5f Merge remote-tracking branch 'upstream/develop' into develop 2017-05-17 20:02:40 +03:00
astaxie
7747e9ec8b Merge branch 'develop' of https://github.com/astaxie/beego into develop 2017-05-17 20:52:53 +08:00
astaxie
9765519f38 Merge pull request #2637 from alexsunxl/develop
allow o.Raw(sql).QueryRows(&container) pass nested struct
2017-05-17 16:45:14 +08:00
astaxie
69f0b94745 fix gosimple 2017-05-16 22:21:43 +08:00
astaxie
3c9b6c99b7 Merge pull request #2643 from rbw0/master
Spelling fixes
2017-05-16 11:26:16 +08:00
Robert Wikman
b5c6eb54d2 Missing PK error spelling fix 2017-05-16 00:58:20 +02:00
Robert Wikman
e1c90bfc09 Table not found spelling fixes 2017-05-16 00:27:57 +02:00
astaxie
91400f10b0 Merge pull request #2640 from franzwilhelm/master
Moved Security to Operation struct to support swagger API security auth
2017-05-14 19:15:20 +08:00
franzwilhelm
c814893d65 add support for global security 2017-05-14 12:13:35 +02:00
alexsunxl
2325090101 add test case that used nested struct test QueryRows 2017-05-14 12:03:34 +08:00
franzwilhelm
40bc52b844 fix security struct placement and formatting 2017-05-14 00:42:09 +02:00
sunxinle
589f3755f0 允许o.Raw(sql).QueryRows(&container) 传入的container包含结构的嵌套 2017-05-12 18:11:42 +08:00
eyalpost
1004678005 popular status codes 2017-05-12 09:57:56 +03:00
eyalpost
0ac2e47162 location=>paramType 2017-05-12 09:28:46 +03:00
eyalpost
b6a35a8944 more tests 2017-05-12 09:25:12 +03:00
Eyal Post
74dc3c7500 tests 2017-05-11 19:32:44 +03:00
Eyal Post
cb4f252a06 defValue -> defaultValue 2017-05-11 17:58:25 +03:00
astaxie
bceefc9075 Merge pull request #2636 from guanly/master
ISSUE2630 使用sqlite,orm中通过filter后的delete删除不成功
2017-05-11 22:04:27 +08:00
guanly
10cd1070f4 使用sqlite,orm中通过filter后的delete删除不成功
https://github.com/astaxie/beego/issues/2630
2017-05-11 21:45:38 +08:00
guanly
9b01b1c63d ISSUE2630 使用sqlite,orm中通过filter后的delete删除不成功
https://github.com/astaxie/beego/issues/2630
2017-05-11 14:49:01 +08:00
Yang Luo
b2e7720fcd Add an authorization plugin that supports ACL, RBAC based on casbin. It requires the built-in HTTP basic authentication by default. 2017-05-04 14:02:21 +08:00
astaxie
83814a76cc hotfix: err nil 2017-05-02 12:47:15 +08:00
Eyal Post
d3a16dca85 Redirect should returns error 2017-05-01 08:57:57 +03:00
astaxie
7452151bee Merge pull request #2611 from astaxie/develop
1.8.2
2017-05-01 13:01:59 +08:00
Eyal Post
1b8f05cef1 golint fixes 2017-04-30 19:28:26 +03:00
Eyal Post
cfb2f68dd6 Merge remote-tracking branch 'upstream/develop' into develop 2017-04-30 18:59:50 +03:00
astaxie
e76423e6dc revert #2518, fix #2605 2017-04-30 23:59:38 +08:00
astaxie
947980b5eb beego 1.8.2 2017-04-30 23:43:46 +08:00
astaxie
44bdf1df63 ignore NilErr 2017-04-30 23:38:48 +08:00
astaxie
79b66ef053 fix the beego ORM test 2017-04-30 22:55:39 +08:00
astaxie
a91e2e9950 add golint check and fix all golints 2017-04-30 22:41:23 +08:00
astaxie
ea3d0690cf golint 2017-04-29 09:13:28 +08:00
astaxie
1c32c011a1 fix misspell 2017-04-28 23:37:40 +08:00
astaxie
64b475d7d6 fix ReadOrCreate test case 2017-04-28 22:58:17 +08:00
astaxie
aa8f7bc146 fix ineffectual 2017-04-28 22:36:28 +08:00
astaxie
3e29078f68 add check ineffect and gofmt 2017-04-28 21:38:08 +08:00
eyalpost
a1bc94e648 dont generate comment if router not found 2017-04-26 01:00:25 +03:00
eyalpost
4cba78afd9 small fixes 2017-04-25 23:42:35 +03:00
ansiz
f311ae9ebe feature: Export function printTree (#2597)
This exports PrintTree function which allow to set Role Based Access Control, Create our own requests statistics...etc
2017-04-25 18:12:03 +02:00
eyalpost
cbd831042a move under context 2017-04-25 18:39:42 +03:00
astaxie
522b3a4a70 Merge pull request #2596 from astaxie/develop
beego 1.8.1
2017-04-25 22:51:23 +08:00
astaxie
cd67f13bf9 add template layout test #2481 2017-04-25 22:21:27 +08:00
astaxie
0f554d9b1a update travis to latest go version 2017-04-25 22:21:08 +08:00
eyalpost
9b79437778 all types working + controller comments generation 2017-04-25 16:00:49 +03:00
astaxie
3742d1178c httplib support delete params fix #2593 2017-04-25 20:42:43 +08:00
xhzhang
b9e3cbbf44 feat: export function printTree
we can do more thing with an exported PrintTree function, such as
  set role base access control,create our own requests statistics.
2017-04-25 12:42:36 +08:00
ansiz
3c0c87f473 Merge pull request #1 from astaxie/master
merge from origin repo
2017-04-25 12:38:32 +08:00
eyalpost
3b29a9c12a Merge remote-tracking branch 'upstream/develop' into develop 2017-04-24 18:23:58 +03:00
astaxie
d03285a0ee Merge pull request #2555 from Liaodd/master
Update ini.go: change the key to lowercase when set a new key for ini configer
2017-04-24 22:37:25 +08:00
astaxie
e810f2e930 add more oracle alias 2017-04-24 21:36:07 +08:00
astaxie
41aac79ac0 Merge pull request #2590 from amrfaissal/fix-2587
Fix warnings raised by gometalinter and gosimple
2017-04-24 21:14:00 +08:00
astaxie
52f916a28a support Go1.8 default GOPATH 2017-04-24 21:10:03 +08:00
eyalpost
864693d2f8 mall fixes 2017-04-24 02:35:04 +03:00
eyalpost
08ea9b3339 Merge remote-tracking branch 'upstream/develop' into develop 2017-04-23 22:07:46 +03:00
Eyal Post
19f4a6ac0b slice support 2017-04-23 21:37:09 +03:00
Faissal Elamraoui
bf6bd6b292 Fixes #2587
Fixes warnings and errors raised by gometalinter and gosimple.
2017-04-23 19:19:05 +02:00
eyalpost
89e01d125c all types implemented 2017-04-23 01:33:50 +03:00
astaxie
3bb4ca5adc Merge pull request #2583 from OlegFX/develop
Fixed InsertOrUpdate bug
2017-04-22 11:19:15 +08:00
OlegFX
712df81c99 Fixed InsertOrUpdate bug 2017-04-21 19:57:04 +03:00
OlegFX
3d7ef599cc Merge pull request #2 from astaxie/develop
Update
2017-04-21 19:50:33 +03:00
eyalpost
9aedb4d05a phase #1 2017-04-21 15:26:41 +03:00
astaxie
453691728a gofmt simplify 2017-04-20 10:56:09 +08:00
astaxie
e7e3ca77ad Merge pull request #2491 from chendx79/master
Fix routing bug for splat matching
2017-04-19 21:20:30 +08:00
astaxie
d3f3956def Merge pull request #2574 from extrlibs/master
Fix the following template reference
2017-04-19 21:18:26 +08:00
astaxie
7206214105 Merge pull request #2575 from PaulChen2016/master
Beego 运行过程中动态增减定时任务时,now的时间需要更新,否则等待时间会不正确
2017-04-19 21:17:38 +08:00
astaxie
b08ace7532 Merge pull request #2577 from ggicci/develop
Fix ini parsing error for multiple users on one machine.
2017-04-19 20:17:45 +08:00
Ggicci
d1a2583972 Fix ini parsing error for multiple users on one machine.
If there were multiple users working on one machine, it's common that
"/tmp/beego" will be owned by one of them, and the others won't be able
to access to it. So, it's better to add an "id-like" postfix to the
temporary directory.
2017-04-19 19:50:11 +08:00
PaulChen2016
0cb8de4218 Beego 运行过程中动态增减定时任务时,now的时间需要更新,否则等待时间会不正确
beego 启动时,执行toolbox.StartTask()
运行过程中,动态添加定时任务(这个是now时间已经不是starttask的时间了,需要刷新)     
     case <-changed:
			now = time.Now().Local()
			continue
2017-04-19 16:22:58 +08:00
Orefa
0cd31a247f fix Template nesting problem 2017-04-19 07:47:05 +08:00
HSoshiant
7886e69236 Update sess_file.go 2017-04-17 12:37:54 -04:00
astaxie
405c170d45 Merge pull request #2556 from zjjott/master
fix: log mode should be 0440 should not be 440
2017-04-10 21:14:34 +08:00
zjjott
932019770d fix: log mode 0440 should not be 440 2017-04-10 17:37:55 +08:00
Liaodd
d5c03f5b8f Update ini.go
change the key to lowercase when set a new key for ini configer
2017-04-10 11:30:23 +08:00
astaxie
3d20c0b8f4 Merge pull request #2543 from Bobochka/fix_route_hander_docs
Fix example for Hander func
2017-04-07 23:04:38 +08:00
Faissal Elamraoui
a4fb4c6a03 Merge pull request #2547 from TrueFurby/patch-1
Update README.md
2017-04-03 20:25:41 +02:00
Ondrej Fabry
a9941b6edc Merge branch 'develop' into patch-1 2017-04-02 13:46:06 +02:00
Ondrej Fabry
6a32b048bd Update README.md 2017-04-02 11:04:08 +02:00
Vladimir Shteinman
fb04d3cff1 Fix example for Hander func 2017-03-30 12:53:12 +03:00
astaxie
5c7673e73d update to 1.8.1 2017-03-29 10:22:27 +08:00
astaxie
54b05377d9 Merge pull request #2466 from gouyang/gouyang/develop
Parse form time by its length
2017-03-29 10:01:03 +08:00
astaxie
f49f3f92ec Merge pull request #2533 from cnxh/redis-session-poolsize
redis poolsize could set to zero
2017-03-29 10:00:28 +08:00
astaxie
b18b94f03b Merge pull request #2539 from astaxie/revert-2421-develop
Revert "close mysql connection"
2017-03-29 09:57:54 +08:00
astaxie
bf469f0b55 Revert "close mysql connection" 2017-03-29 09:57:18 +08:00
astaxie
c12709dbc9 Merge pull request #2536 from ChristophPech/master
Fix for IndexExists in SQLite driver
2017-03-29 09:53:55 +08:00
Christoph Pech
2808a13f07 Fix for IndexExists in SQLite driver, they added the "origin" and "partial" columns to the index_list pragma.
see: https://www.sqlite.org/src/info/2743846cdba572f6
2017-03-28 12:38:27 +02:00
Faissal Elamraoui
a8d48aa5ea Merge pull request #2535 from ketanhwr/patch-1
Update README.md
2017-03-28 10:49:52 +02:00
Ketan Gupta
fdb2660a2a Update README.md 2017-03-28 11:29:20 +05:30
xia hao
7c3a997735 poolsize could set to zero
sometimes we may want disable the redis pool
2017-03-27 23:34:58 +08:00
astaxie
1760f0ceca Merge pull request #2532 from vbalien/patch-1
Fix markdown formatting
2017-03-27 13:34:19 +08:00
Jisu Kim
c387aeeb36 fix markdown formatting 2017-03-27 14:30:42 +09:00
Guohua Ouyang
83d4385f1f Support time.RFC3339
Signed-off-by: Guohua Ouyang <guohuaouyang@gmail.com>
2017-03-25 07:52:43 +08:00
astaxie
ae0a75c464 console debug use diffrent color 2017-03-21 23:55:40 +08:00
astaxie
a05e5a7c09 Merge branches 'master' and 'develop' of https://github.com/astaxie/beego into develop 2017-03-21 23:47:32 +08:00
astaxie
75ca7b77b6 Merge pull request #2518 from sicojuy/develop
Fix set cookie bug, zero max age is not valid.
2017-03-21 09:44:37 +08:00
liaoziqian
b0e2012a17 Fix set cookie bug, zero max age is not valid. 2017-03-21 09:15:30 +08:00
astaxie
12dff072fa Merge pull request #2509 from sergeylanzman/add-gosimple
add go simple support
2017-03-18 13:37:31 +08:00
astaxie
d956444965 Merge branch 'develop' into add-gosimple 2017-03-18 11:20:30 +08:00
astaxie
8dbf9eb0bf Merge pull request #2512 from sergeylanzman/add-unconvert
add unconverted support
2017-03-18 11:05:28 +08:00
astaxie
faa981fb6a Merge pull request #2511 from sergeylanzman/drop-go1.4-1.5-travis
drop support go1.4/5 in travis yml
2017-03-18 11:02:39 +08:00
astaxie
1ea3c13ff5 Merge branch 'develop' into drop-go1.4-1.5-travis 2017-03-18 11:02:15 +08:00
astaxie
46d8fef0ad Merge pull request #2510 from sergeylanzman/travis-add-1.7-1.8
add support go1.7/8 to travis yml
2017-03-18 11:01:27 +08:00
Sergey Lanzman
37c1ffc57a add go simple support 2017-03-17 20:22:20 +02:00
Sergey Lanzman
856fde28dc add unconverted support 2017-03-17 19:45:30 +02:00
Sergey Lanzman
3204d7631b drop support go1.4/5 in travis yml 2017-03-17 19:33:54 +02:00
Sergey Lanzman
f5fc2edfd3 add support go1.7/8 to travis yml 2017-03-17 19:32:31 +02:00
astaxie
21d1267c14 Merge pull request #2501 from sergeylanzman/change-template-error-log
temple parse error write in log as trace. change to error
2017-03-14 20:04:42 +08:00
Sergey Lanzman
3e37b97549 temple parse error write in log as trace. change to error 2017-03-14 12:55:40 +02:00
astaxie
206f736819 Merge pull request #2496 from eyalpost/develop
Don't panic during AddViewPath if adding the same path twice
2017-03-14 12:54:48 +08:00
Eyal Post
24d4a27842 Don't panic during AddViewPath if adding the same path twice 2017-03-13 08:46:57 +02:00
astaxie
46f3ea4f43 Merge pull request #2494 from miraclesu/develop
validation: fix email valid
2017-03-12 22:26:25 +08:00
miraclesu
c9cc642d37 validation: amend email test case 2017-03-12 20:27:09 +08:00
miraclesu
b34853f8cc validattion: add test case for email valid 2017-03-12 19:30:23 +08:00
miraclesu
d41f4c0a3a validation: fix email valid 2017-03-12 19:23:46 +08:00
chendingxing
8e46decc8e fix routing bug for splat 2017-03-10 09:28:25 +08:00
Guohua Ouyang
49fffe3ebe Parse form time by its length
Fix #2451

Signed-off-by: Guohua Ouyang <guohuaouyang@gmail.com>
2017-02-27 14:43:16 +08:00
chesedo
a8a2dffc59 Have Required validator trim strings to fix #2361
This will cause the Required validator not to consider fields that has
only spaces or new lines to be regarded as valid. This is done by
checking if the trimmed version of the string is valid.
2017-01-06 10:12:22 +02:00
173 changed files with 8012 additions and 2729 deletions

View File

@ -1,19 +1,26 @@
language: go
go:
- 1.6
- 1.5.3
- 1.4.3
- "1.13.x"
services:
- redis-server
- mysql
- postgresql
- memcached
env:
- ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
- ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8"
- ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
global:
- GO_REPO_FULLNAME="github.com/astaxie/beego"
matrix:
- ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
- ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
before_install:
# link the local repo with ${GOPATH}/src/<namespace>/<repo>
- GO_REPO_NAMESPACE=${GO_REPO_FULLNAME%/*}
# relies on GOPATH to contain only one directory...
- mkdir -p ${GOPATH}/src/${GO_REPO_NAMESPACE}
- ln -sv ${TRAVIS_BUILD_DIR} ${GOPATH}/src/${GO_REPO_FULLNAME}
- cd ${GOPATH}/src/${GO_REPO_FULLNAME}
# get and build ssdb
- git clone git://github.com/ideawu/ssdb.git
- cd ssdb
- make
@ -23,29 +30,44 @@ install:
- go get github.com/go-sql-driver/mysql
- go get github.com/mattn/go-sqlite3
- go get github.com/bradfitz/gomemcache/memcache
- go get github.com/garyburd/redigo/redis
- go get github.com/gomodule/redigo/redis
- go get github.com/beego/x2j
- go get github.com/couchbase/go-couchbase
- go get github.com/beego/goyaml2
- go get gopkg.in/yaml.v2
- go get github.com/belogik/goes
- go get github.com/siddontang/ledisdb/config
- go get github.com/siddontang/ledisdb/ledis
- go get github.com/ledisdb/ledisdb
- go get github.com/ssdb/gossdb/ssdb
- go get github.com/cloudflare/golz4
- go get github.com/gogo/protobuf/proto
- go get github.com/Knetic/govaluate
- go get github.com/casbin/casbin
- go get github.com/elazarl/go-bindata-assetfs
- go get github.com/OwnLocal/goes
- go get github.com/shiena/ansicolor
- go get -u honnef.co/go/tools/cmd/staticcheck
- go get -u github.com/mdempsky/unconvert
- go get -u github.com/gordonklaus/ineffassign
- go get -u golang.org/x/lint/golint
- go get -u github.com/go-redis/redis
before_script:
- psql --version
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
- sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
- sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
- sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi"
- sh -c "if [ $(go version) == *1.[5-9]* ]; then go tool vet .; fi"
- sh -c "go get github.com/golang/lint/golint; golint ./...;"
- sh -c "go list ./... | grep -v vendor | xargs go vet -v"
- mkdir -p res/var
- ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
after_script:
-killall -w ssdb-server
- killall -w ssdb-server
- rm -rf ./res/var/*
script:
- go test -v ./...
- staticcheck -show-ignored -checks "-ST1017,-U1000,-ST1005,-S1034,-S1012,-SA4006,-SA6005,-SA1019,-SA1024"
- unconvert $(go list ./... | grep -v /vendor/)
- ineffassign .
- find . ! \( -path './vendor' -prune \) -type f -name '*.go' -print0 | xargs -0 gofmt -l -s
- golint ./...
addons:
postgresql: "9.4"
postgresql: "9.6"

View File

@ -1,20 +1,18 @@
## Beego
# Beego [![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) [![Go Report Card](https://goreportcard.com/badge/github.com/astaxie/beego)](https://goreportcard.com/report/github.com/astaxie/beego)
[![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego)
[![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego)
[![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org)
beego is used for rapid development of RESTful APIs, web apps and backend services in Go.
It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.
More info [beego.me](http://beego.me)
###### More info at [beego.me](http://beego.me).
##Quick Start
######Download and install
## Quick Start
#### Download and install
go get github.com/astaxie/beego
######Create file `hello.go`
#### Create file `hello.go`
```go
package main
@ -24,15 +22,18 @@ func main(){
beego.Run()
}
```
######Build and run
```bash
#### Build and run
go build hello.go
./hello
```
######Congratulations!
You just built your first beego app.
Open your browser and visit `http://localhost:8080`.
Please see [Documentation](http://beego.me/docs) for more.
#### Go to [http://localhost:8080](http://localhost:8080)
Congratulations! You've just built your first **beego** app.
###### Please see [Documentation](http://beego.me/docs) for more.
###### [beego-example](https://github.com/beego-dev/beego-example)
## Features
@ -55,8 +56,9 @@ Please see [Documentation](http://beego.me/docs) for more.
* [http://beego.me/community](http://beego.me/community)
* Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited from [here](https://github.com/beego/beedoc/issues/232)
* QQ Group Group ID:523992905
## LICENSE
## License
beego source code is licensed under the Apache Licence, Version 2.0
(http://www.apache.org/licenses/LICENSE-2.0.html).

157
admin.go
View File

@ -20,10 +20,11 @@ import (
"fmt"
"net/http"
"os"
"reflect"
"text/template"
"time"
"reflect"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/astaxie/beego/grace"
"github.com/astaxie/beego/logs"
@ -35,9 +36,9 @@ import (
var beeAdminApp *adminApp
// FilterMonitorFunc is default monitor filter when admin module is enable.
// if this func returns, admin module records qbs for this request by condition of this function logic.
// if this func returns, admin module records qps for this request by condition of this function logic.
// usage:
// func MyFilterMonitor(method, requestPath string, t time.Duration) bool {
// func MyFilterMonitor(method, requestPath string, t time.Duration, pattern string, statusCode int) bool {
// if method == "POST" {
// return false
// }
@ -50,32 +51,46 @@ var beeAdminApp *adminApp
// return true
// }
// beego.FilterMonitorFunc = MyFilterMonitor.
var FilterMonitorFunc func(string, string, time.Duration) bool
var FilterMonitorFunc func(string, string, time.Duration, string, int) bool
func init() {
beeAdminApp = &adminApp{
routers: make(map[string]http.HandlerFunc),
}
// keep in mind that all data should be html escaped to avoid XSS attack
beeAdminApp.Route("/", adminIndex)
beeAdminApp.Route("/qps", qpsIndex)
beeAdminApp.Route("/prof", profIndex)
beeAdminApp.Route("/healthcheck", healthcheck)
beeAdminApp.Route("/task", taskStatus)
beeAdminApp.Route("/listconf", listConf)
FilterMonitorFunc = func(string, string, time.Duration) bool { return true }
beeAdminApp.Route("/metrics", promhttp.Handler().ServeHTTP)
FilterMonitorFunc = func(string, string, time.Duration, string, int) bool { return true }
}
// AdminIndex is the default http.Handler for admin module.
// it matches url pattern "/".
func adminIndex(rw http.ResponseWriter, r *http.Request) {
func adminIndex(rw http.ResponseWriter, _ *http.Request) {
execTpl(rw, map[interface{}]interface{}{}, indexTpl, defaultScriptsTpl)
}
// QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter.
// it's registered with url pattern "/qbs" in admin module.
func qpsIndex(rw http.ResponseWriter, r *http.Request) {
// QpsIndex is the http.Handler for writing qps statistics map result info in http.ResponseWriter.
// it's registered with url pattern "/qps" in admin module.
func qpsIndex(rw http.ResponseWriter, _ *http.Request) {
data := make(map[interface{}]interface{})
data["Content"] = toolbox.StatisticsMap.GetMap()
// do html escape before display path, avoid xss
if content, ok := (data["Content"]).(M); ok {
if resultLists, ok := (content["Data"]).([][]string); ok {
for i := range resultLists {
if len(resultLists[i]) > 0 {
resultLists[i][0] = template.HTMLEscapeString(resultLists[i][0])
}
}
}
}
execTpl(rw, data, qpsTpl, defaultScriptsTpl)
}
@ -92,10 +107,10 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
data := make(map[interface{}]interface{})
switch command {
case "conf":
m := make(map[string]interface{})
m := make(M)
list("BConfig", BConfig, m)
m["AppConfigPath"] = appConfigPath
m["AppConfigProvider"] = appConfigProvider
m["AppConfigPath"] = template.HTMLEscapeString(appConfigPath)
m["AppConfigProvider"] = template.HTMLEscapeString(appConfigProvider)
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
tmpl = template.Must(tmpl.Parse(configTpl))
tmpl = template.Must(tmpl.Parse(defaultScriptsTpl))
@ -105,42 +120,25 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
tmpl.Execute(rw, data)
case "router":
var (
content = map[string]interface{}{
"Fields": []string{
"Router Pattern",
"Methods",
"Controller",
},
}
methods = []string{}
methodsData = make(map[string]interface{})
)
for method, t := range BeeApp.Handlers.routers {
resultList := new([][]string)
printTree(resultList, t)
methods = append(methods, method)
methodsData[method] = resultList
content := PrintTree()
content["Fields"] = []string{
"Router Pattern",
"Methods",
"Controller",
}
content["Data"] = methodsData
content["Methods"] = methods
data["Content"] = content
data["Title"] = "Routers"
execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl)
case "filter":
var (
content = map[string]interface{}{
content = M{
"Fields": []string{
"Router Pattern",
"Filter Function",
},
}
filterTypes = []string{}
filterTypeData = make(map[string]interface{})
filterTypeData = make(M)
)
if BeeApp.Handlers.enableFilter {
@ -157,8 +155,9 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
resultList := new([][]string)
for _, f := range bf {
var result = []string{
fmt.Sprintf("%s", f.pattern),
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
// void xss
template.HTMLEscapeString(f.pattern),
template.HTMLEscapeString(utils.GetFuncName(f.filterFunc)),
}
*resultList = append(*resultList, result)
}
@ -178,7 +177,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
}
}
func list(root string, p interface{}, m map[string]interface{}) {
func list(root string, p interface{}, m M) {
pt := reflect.TypeOf(p)
pv := reflect.ValueOf(p)
if pt.Kind() == reflect.Ptr {
@ -200,6 +199,28 @@ func list(root string, p interface{}, m map[string]interface{}) {
}
}
// PrintTree prints all registered routers.
func PrintTree() M {
var (
content = M{}
methods = []string{}
methodsData = make(M)
)
for method, t := range BeeApp.Handlers.routers {
resultList := new([][]string)
printTree(resultList, t)
methods = append(methods, template.HTMLEscapeString(method))
methodsData[template.HTMLEscapeString(method)] = resultList
}
content["Data"] = methodsData
content["Methods"] = methods
return content
}
func printTree(resultList *[][]string, t *Tree) {
for _, tr := range t.fixrouters {
printTree(resultList, tr)
@ -208,24 +229,24 @@ func printTree(resultList *[][]string, t *Tree) {
printTree(resultList, t.wildcard)
}
for _, l := range t.leaves {
if v, ok := l.runObject.(*controllerInfo); ok {
if v, ok := l.runObject.(*ControllerInfo); ok {
if v.routerType == routerTypeBeego {
var result = []string{
v.pattern,
fmt.Sprintf("%s", v.methods),
fmt.Sprintf("%s", v.controllerType),
template.HTMLEscapeString(v.pattern),
template.HTMLEscapeString(fmt.Sprintf("%s", v.methods)),
template.HTMLEscapeString(v.controllerType.String()),
}
*resultList = append(*resultList, result)
} else if v.routerType == routerTypeRESTFul {
var result = []string{
v.pattern,
fmt.Sprintf("%s", v.methods),
template.HTMLEscapeString(v.pattern),
template.HTMLEscapeString(fmt.Sprintf("%s", v.methods)),
"",
}
*resultList = append(*resultList, result)
} else if v.routerType == routerTypeHandler {
var result = []string{
v.pattern,
template.HTMLEscapeString(v.pattern),
"",
"",
}
@ -250,7 +271,7 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
result bytes.Buffer
)
toolbox.ProcessInput(command, &result)
data["Content"] = result.String()
data["Content"] = template.HTMLEscapeString(result.String())
if format == "json" && command == "gc summary" {
dataJSON, err := json.Marshal(data)
@ -264,7 +285,7 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
return
}
data["Title"] = command
data["Title"] = template.HTMLEscapeString(command)
defaultTpl := defaultScriptsTpl
if command == "gc summary" {
defaultTpl = gcAjaxTpl
@ -274,12 +295,12 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
// Healthcheck is a http.Handler calling health checking and showing the result.
// it's in "/healthcheck" pattern in admin module.
func healthcheck(rw http.ResponseWriter, req *http.Request) {
func healthcheck(rw http.ResponseWriter, _ *http.Request) {
var (
result []string
data = make(map[interface{}]interface{})
result = []string{}
resultList = new([][]string)
content = map[string]interface{}{
content = M{
"Fields": []string{"Name", "Message", "Status"},
}
)
@ -287,21 +308,20 @@ func healthcheck(rw http.ResponseWriter, req *http.Request) {
for name, h := range toolbox.AdminCheckList {
if err := h.Check(); err != nil {
result = []string{
fmt.Sprintf("error"),
fmt.Sprintf("%s", name),
fmt.Sprintf("%s", err.Error()),
"error",
template.HTMLEscapeString(name),
template.HTMLEscapeString(err.Error()),
}
} else {
result = []string{
fmt.Sprintf("success"),
fmt.Sprintf("%s", name),
fmt.Sprintf("OK"),
"success",
template.HTMLEscapeString(name),
"OK",
}
}
*resultList = append(*resultList, result)
}
content["Data"] = resultList
data["Content"] = content
data["Title"] = "Health Check"
@ -319,18 +339,17 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
if taskname != "" {
if t, ok := toolbox.AdminTaskList[taskname]; ok {
if err := t.Run(); err != nil {
data["Message"] = []string{"error", fmt.Sprintf("%s", err)}
data["Message"] = []string{"error", template.HTMLEscapeString(fmt.Sprintf("%s", err))}
}
data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is <br>%s", taskname, t.GetStatus())}
data["Message"] = []string{"success", template.HTMLEscapeString(fmt.Sprintf("%s run success,Now the Status is <br>%s", taskname, t.GetStatus()))}
} else {
data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)}
data["Message"] = []string{"warning", template.HTMLEscapeString(fmt.Sprintf("there's no task which named: %s", taskname))}
}
}
// List Tasks
content := make(map[string]interface{})
content := make(M)
resultList := new([][]string)
var result = []string{}
var fields = []string{
"Task Name",
"Task Spec",
@ -339,11 +358,11 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
"",
}
for tname, tk := range toolbox.AdminTaskList {
result = []string{
tname,
fmt.Sprintf("%s", tk.GetSpec()),
fmt.Sprintf("%s", tk.GetStatus()),
tk.GetPrev().String(),
result := []string{
template.HTMLEscapeString(tname),
template.HTMLEscapeString(tk.GetSpec()),
template.HTMLEscapeString(tk.GetStatus()),
template.HTMLEscapeString(tk.GetPrev().String()),
}
*resultList = append(*resultList, result)
}

View File

@ -6,7 +6,7 @@ import (
)
func TestList_01(t *testing.T) {
m := make(map[string]interface{})
m := make(M)
list("BConfig", BConfig, m)
t.Log(m)
om := oldMap()
@ -18,8 +18,8 @@ func TestList_01(t *testing.T) {
}
}
func oldMap() map[string]interface{} {
m := make(map[string]interface{})
func oldMap() M {
m := make(M)
m["BConfig.AppName"] = BConfig.AppName
m["BConfig.RunMode"] = BConfig.RunMode
m["BConfig.RouterCaseSensitive"] = BConfig.RouterCaseSensitive
@ -52,6 +52,8 @@ func oldMap() map[string]interface{} {
m["BConfig.WebConfig.DirectoryIndex"] = BConfig.WebConfig.DirectoryIndex
m["BConfig.WebConfig.StaticDir"] = BConfig.WebConfig.StaticDir
m["BConfig.WebConfig.StaticExtensionsToGzip"] = BConfig.WebConfig.StaticExtensionsToGzip
m["BConfig.WebConfig.StaticCacheFileSize"] = BConfig.WebConfig.StaticCacheFileSize
m["BConfig.WebConfig.StaticCacheFileNum"] = BConfig.WebConfig.StaticCacheFileNum
m["BConfig.WebConfig.TemplateLeft"] = BConfig.WebConfig.TemplateLeft
m["BConfig.WebConfig.TemplateRight"] = BConfig.WebConfig.TemplateRight
m["BConfig.WebConfig.ViewsPath"] = BConfig.WebConfig.ViewsPath
@ -67,6 +69,8 @@ func oldMap() map[string]interface{} {
m["BConfig.WebConfig.Session.SessionDomain"] = BConfig.WebConfig.Session.SessionDomain
m["BConfig.WebConfig.Session.SessionDisableHTTPOnly"] = BConfig.WebConfig.Session.SessionDisableHTTPOnly
m["BConfig.Log.AccessLogs"] = BConfig.Log.AccessLogs
m["BConfig.Log.EnableStaticLogs"] = BConfig.Log.EnableStaticLogs
m["BConfig.Log.AccessLogsFormat"] = BConfig.Log.AccessLogsFormat
m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum
m["BConfig.Log.Outputs"] = BConfig.Log.Outputs
return m

162
app.go
View File

@ -15,17 +15,22 @@
package beego
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/fcgi"
"os"
"path"
"strings"
"time"
"github.com/astaxie/beego/grace"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/utils"
"golang.org/x/crypto/acme/autocert"
)
var (
@ -51,8 +56,11 @@ func NewApp() *App {
return app
}
// MiddleWare function for http.Handler
type MiddleWare func(http.Handler) http.Handler
// Run beego application.
func (app *App) Run() {
func (app *App) Run(mws ...MiddleWare) {
addr := BConfig.Listen.HTTPAddr
if BConfig.Listen.HTTPPort != 0 {
@ -94,6 +102,12 @@ func (app *App) Run() {
}
app.Server.Handler = app.Handlers
for i := len(mws) - 1; i >= 0; i-- {
if mws[i] == nil {
continue
}
app.Server.Handler = mws[i](app.Server.Handler)
}
app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
app.Server.ErrorLog = logs.GetLogger("HTTP")
@ -102,26 +116,42 @@ func (app *App) Run() {
if BConfig.Listen.Graceful {
httpsAddr := BConfig.Listen.HTTPSAddr
app.Server.Addr = httpsAddr
if BConfig.Listen.EnableHTTPS {
if BConfig.Listen.EnableHTTPS || BConfig.Listen.EnableMutualHTTPS {
go func() {
time.Sleep(20 * time.Microsecond)
time.Sleep(1000 * time.Microsecond)
if BConfig.Listen.HTTPSPort != 0 {
httpsAddr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
app.Server.Addr = httpsAddr
}
server := grace.NewServer(httpsAddr, app.Handlers)
server := grace.NewServer(httpsAddr, app.Server.Handler)
server.Server.ReadTimeout = app.Server.ReadTimeout
server.Server.WriteTimeout = app.Server.WriteTimeout
if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
time.Sleep(100 * time.Microsecond)
endRunning <- true
if BConfig.Listen.EnableMutualHTTPS {
if err := server.ListenAndServeMutualTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile, BConfig.Listen.TrustCaFile); err != nil {
logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
time.Sleep(100 * time.Microsecond)
}
} else {
if BConfig.Listen.AutoTLS {
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(BConfig.Listen.Domains...),
Cache: autocert.DirCache(BConfig.Listen.TLSCacheDir),
}
app.Server.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate}
BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile = "", ""
}
if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
time.Sleep(100 * time.Microsecond)
}
}
endRunning <- true
}()
}
if BConfig.Listen.EnableHTTP {
go func() {
server := grace.NewServer(addr, app.Handlers)
server := grace.NewServer(addr, app.Server.Handler)
server.Server.ReadTimeout = app.Server.ReadTimeout
server.Server.WriteTimeout = app.Server.WriteTimeout
if BConfig.Listen.ListenTCP4 {
@ -130,8 +160,8 @@ func (app *App) Run() {
if err := server.ListenAndServe(); err != nil {
logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
time.Sleep(100 * time.Microsecond)
endRunning <- true
}
endRunning <- true
}()
}
<-endRunning
@ -139,22 +169,44 @@ func (app *App) Run() {
}
// run normal mode
if BConfig.Listen.EnableHTTPS {
if BConfig.Listen.EnableHTTPS || BConfig.Listen.EnableMutualHTTPS {
go func() {
time.Sleep(20 * time.Microsecond)
time.Sleep(1000 * time.Microsecond)
if BConfig.Listen.HTTPSPort != 0 {
app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
} else if BConfig.Listen.EnableHTTP {
BeeLogger.Info("Start https server error, confict with http.Please reset https port")
logs.Info("Start https server error, conflict with http. Please reset https port")
return
}
logs.Info("https server Running on https://%s", app.Server.Addr)
if BConfig.Listen.AutoTLS {
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(BConfig.Listen.Domains...),
Cache: autocert.DirCache(BConfig.Listen.TLSCacheDir),
}
app.Server.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate}
BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile = "", ""
} else if BConfig.Listen.EnableMutualHTTPS {
pool := x509.NewCertPool()
data, err := ioutil.ReadFile(BConfig.Listen.TrustCaFile)
if err != nil {
logs.Info("MutualHTTPS should provide TrustCaFile")
return
}
pool.AppendCertsFromPEM(data)
app.Server.TLSConfig = &tls.Config{
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
}
}
if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
logs.Critical("ListenAndServeTLS: ", err)
time.Sleep(100 * time.Microsecond)
endRunning <- true
}
}()
}
if BConfig.Listen.EnableHTTP {
go func() {
@ -207,6 +259,84 @@ func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *A
return BeeApp
}
// UnregisterFixedRoute unregisters the route with the specified fixedRoute. It is particularly useful
// in web applications that inherit most routes from a base webapp via the underscore
// import, and aim to overwrite only certain paths.
// The method parameter can be empty or "*" for all HTTP methods, or a particular
// method type (e.g. "GET" or "POST") for selective removal.
//
// Usage (replace "GET" with "*" for all methods):
// beego.UnregisterFixedRoute("/yourpreviouspath", "GET")
// beego.Router("/yourpreviouspath", yourControllerAddress, "get:GetNewPage")
func UnregisterFixedRoute(fixedRoute string, method string) *App {
subPaths := splitPath(fixedRoute)
if method == "" || method == "*" {
for m := range HTTPMETHOD {
if _, ok := BeeApp.Handlers.routers[m]; !ok {
continue
}
if BeeApp.Handlers.routers[m].prefix == strings.Trim(fixedRoute, "/ ") {
findAndRemoveSingleTree(BeeApp.Handlers.routers[m])
continue
}
findAndRemoveTree(subPaths, BeeApp.Handlers.routers[m], m)
}
return BeeApp
}
// Single HTTP method
um := strings.ToUpper(method)
if _, ok := BeeApp.Handlers.routers[um]; ok {
if BeeApp.Handlers.routers[um].prefix == strings.Trim(fixedRoute, "/ ") {
findAndRemoveSingleTree(BeeApp.Handlers.routers[um])
return BeeApp
}
findAndRemoveTree(subPaths, BeeApp.Handlers.routers[um], um)
}
return BeeApp
}
func findAndRemoveTree(paths []string, entryPointTree *Tree, method string) {
for i := range entryPointTree.fixrouters {
if entryPointTree.fixrouters[i].prefix == paths[0] {
if len(paths) == 1 {
if len(entryPointTree.fixrouters[i].fixrouters) > 0 {
// If the route had children subtrees, remove just the functional leaf,
// to allow children to function as before
if len(entryPointTree.fixrouters[i].leaves) > 0 {
entryPointTree.fixrouters[i].leaves[0] = nil
entryPointTree.fixrouters[i].leaves = entryPointTree.fixrouters[i].leaves[1:]
}
} else {
// Remove the *Tree from the fixrouters slice
entryPointTree.fixrouters[i] = nil
if i == len(entryPointTree.fixrouters)-1 {
entryPointTree.fixrouters = entryPointTree.fixrouters[:i]
} else {
entryPointTree.fixrouters = append(entryPointTree.fixrouters[:i], entryPointTree.fixrouters[i+1:len(entryPointTree.fixrouters)]...)
}
}
return
}
findAndRemoveTree(paths[1:], entryPointTree.fixrouters[i], method)
}
}
}
func findAndRemoveSingleTree(entryPointTree *Tree) {
if entryPointTree == nil {
return
}
if len(entryPointTree.fixrouters) > 0 {
// If the route had children subtrees, remove just the functional leaf,
// to allow children to function as before
if len(entryPointTree.leaves) > 0 {
entryPointTree.leaves[0] = nil
entryPointTree.leaves = entryPointTree.leaves[1:]
}
}
}
// Include will generate router file in the router/xxx.go from the controller's comments
// usage:
// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
@ -348,9 +478,9 @@ func Any(rootpath string, f FilterFunc) *App {
// Handler used to register a Handler router
// usage:
// beego.Handler("/api", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
// beego.Handler("/api", http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
// fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
// }))
func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
BeeApp.Handlers.Handler(rootpath, h, options...)
return BeeApp

View File

@ -23,7 +23,7 @@ import (
const (
// VERSION represent beego web framework version.
VERSION = "1.8.0"
VERSION = "1.12.2"
// DEV is for develop
DEV = "dev"
@ -31,7 +31,10 @@ const (
PROD = "prod"
)
//hook function to run
// M is Map shortcut
type M map[string]interface{}
// Hook function to run
type hookfunc func() error
var (
@ -40,9 +43,9 @@ var (
// AddAPPStartHook is used to register the hookfunc
// The hookfuncs will run in beego.Run()
// such as sessionInit, middlerware start, buildtemplate, admin start
func AddAPPStartHook(hf hookfunc) {
hooks = append(hooks, hf)
// such as initiating session , starting middleware , building template, starting admin control and so on.
func AddAPPStartHook(hf ...hookfunc) {
hooks = append(hooks, hf...)
}
// Run beego application.
@ -62,19 +65,39 @@ func Run(params ...string) {
if len(strs) > 1 && strs[1] != "" {
BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
}
BConfig.Listen.Domains = params
}
BeeApp.Run()
}
// RunWithMiddleWares Run beego application with middlewares.
func RunWithMiddleWares(addr string, mws ...MiddleWare) {
initBeforeHTTPRun()
strs := strings.Split(addr, ":")
if len(strs) > 0 && strs[0] != "" {
BConfig.Listen.HTTPAddr = strs[0]
BConfig.Listen.Domains = []string{strs[0]}
}
if len(strs) > 1 && strs[1] != "" {
BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
}
BeeApp.Run(mws...)
}
func initBeforeHTTPRun() {
//init hooks
AddAPPStartHook(registerMime)
AddAPPStartHook(registerDefaultErrorHandler)
AddAPPStartHook(registerSession)
AddAPPStartHook(registerTemplate)
AddAPPStartHook(registerAdmin)
AddAPPStartHook(registerGzip)
AddAPPStartHook(
registerMime,
registerDefaultErrorHandler,
registerSession,
registerTemplate,
registerAdmin,
registerGzip,
)
for _, hk := range hooks {
if err := hk(); err != nil {

View File

@ -1,10 +1,10 @@
// Copyright 2014 beego Author. All Rights Reserved.
// Copyright 2020 astaxie
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@ -12,17 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows
package beego
package logs
var (
BuildVersion string
BuildGitRevision string
BuildStatus string
BuildTag string
BuildTime string
import "io"
GoVersion string
type ansiColorWriter struct {
w io.Writer
mode outputMode
}
func (cw *ansiColorWriter) Write(p []byte) (int, error) {
return cw.w.Write(p)
}
GitBranch string
)

2
cache/README.md vendored
View File

@ -52,7 +52,7 @@ Configure like this:
## Redis adapter
Redis adapter use the [redigo](http://github.com/garyburd/redigo) client.
Redis adapter use the [redigo](http://github.com/gomodule/redigo) client.
Configure like this:

2
cache/cache.go vendored
View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package cache provide a Cache interface and some implemetn engine
// Package cache provide a Cache interface and some implement engine
// Usage:
//
// import(

25
cache/cache_test.go vendored
View File

@ -16,10 +16,33 @@ package cache
import (
"os"
"sync"
"testing"
"time"
)
func TestCacheIncr(t *testing.T) {
bm, err := NewCache("memory", `{"interval":20}`)
if err != nil {
t.Error("init err")
}
//timeoutDuration := 10 * time.Second
bm.Put("edwardhey", 0, time.Second*20)
wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
bm.Incr("edwardhey")
}()
}
wg.Wait()
if bm.Get("edwardhey").(int) != 10 {
t.Error("Incr err")
}
}
func TestCache(t *testing.T) {
bm, err := NewCache("memory", `{"interval":20}`)
if err != nil {
@ -98,7 +121,7 @@ func TestCache(t *testing.T) {
}
func TestFileCache(t *testing.T) {
bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":"2","EmbedExpiry":"0"}`)
if err != nil {
t.Error("init err")
}

2
cache/conv.go vendored
View File

@ -28,7 +28,7 @@ func GetString(v interface{}) string {
return string(result)
default:
if v != nil {
return fmt.Sprintf("%v", result)
return fmt.Sprint(result)
}
}
return ""

6
cache/conv_test.go vendored
View File

@ -118,14 +118,14 @@ func TestGetFloat64(t *testing.T) {
func TestGetBool(t *testing.T) {
var t1 = true
if true != GetBool(t1) {
if !GetBool(t1) {
t.Error("get bool from bool error")
}
var t2 = "true"
if true != GetBool(t2) {
if !GetBool(t2) {
t.Error("get bool from string error")
}
if false != GetBool(nil) {
if GetBool(nil) {
t.Error("get bool from nil error")
}
}

17
cache/file.go vendored
View File

@ -62,11 +62,14 @@ func NewFileCache() Cache {
}
// StartAndGC will start and begin gc for file cache.
// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":"2","EmbedExpiry":"0"}
func (fc *FileCache) StartAndGC(config string) error {
var cfg map[string]string
json.Unmarshal([]byte(config), &cfg)
cfg := make(map[string]string)
err := json.Unmarshal([]byte(config), &cfg)
if err != nil {
return err
}
if _, ok := cfg["CachePath"]; !ok {
cfg["CachePath"] = FileCachePath
}
@ -142,12 +145,12 @@ func (fc *FileCache) GetMulti(keys []string) []interface{} {
// Put value into file cache.
// timeout means how long to keep this file, unit of ms.
// if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever.
// if timeout equals fc.EmbedExpiry(default is 0), cache this item forever.
func (fc *FileCache) Put(key string, val interface{}, timeout time.Duration) error {
gob.Register(val)
item := FileCacheItem{Data: val}
if timeout == FileCacheEmbedExpiry {
if timeout == time.Duration(fc.EmbedExpiry) {
item.Expired = time.Now().Add((86400 * 365 * 10) * time.Second) // ten years
} else {
item.Expired = time.Now().Add(timeout)
@ -179,7 +182,7 @@ func (fc *FileCache) Incr(key string) error {
} else {
incr = data.(int) + 1
}
fc.Put(key, incr, FileCacheEmbedExpiry)
fc.Put(key, incr, time.Duration(fc.EmbedExpiry))
return nil
}
@ -192,7 +195,7 @@ func (fc *FileCache) Decr(key string) error {
} else {
decr = data.(int) - 1
}
fc.Put(key, decr, FileCacheEmbedExpiry)
fc.Put(key, decr, time.Duration(fc.EmbedExpiry))
return nil
}

View File

@ -146,10 +146,7 @@ func (rc *Cache) IsExist(key string) bool {
}
}
_, err := rc.conn.Get(key)
if err != nil {
return false
}
return true
return err == nil
}
// ClearAll clear all cached in memcache.

86
cache/memory.go vendored
View File

@ -110,25 +110,25 @@ func (bc *MemoryCache) Delete(name string) error {
// Incr increase cache counter in memory.
// it supports int,int32,int64,uint,uint32,uint64.
func (bc *MemoryCache) Incr(key string) error {
bc.RLock()
defer bc.RUnlock()
bc.Lock()
defer bc.Unlock()
itm, ok := bc.items[key]
if !ok {
return errors.New("key not exist")
}
switch itm.val.(type) {
switch val := itm.val.(type) {
case int:
itm.val = itm.val.(int) + 1
itm.val = val + 1
case int32:
itm.val = itm.val.(int32) + 1
itm.val = val + 1
case int64:
itm.val = itm.val.(int64) + 1
itm.val = val + 1
case uint:
itm.val = itm.val.(uint) + 1
itm.val = val + 1
case uint32:
itm.val = itm.val.(uint32) + 1
itm.val = val + 1
case uint64:
itm.val = itm.val.(uint64) + 1
itm.val = val + 1
default:
return errors.New("item val is not (u)int (u)int32 (u)int64")
}
@ -137,34 +137,34 @@ func (bc *MemoryCache) Incr(key string) error {
// Decr decrease counter in memory.
func (bc *MemoryCache) Decr(key string) error {
bc.RLock()
defer bc.RUnlock()
bc.Lock()
defer bc.Unlock()
itm, ok := bc.items[key]
if !ok {
return errors.New("key not exist")
}
switch itm.val.(type) {
switch val := itm.val.(type) {
case int:
itm.val = itm.val.(int) - 1
itm.val = val - 1
case int64:
itm.val = itm.val.(int64) - 1
itm.val = val - 1
case int32:
itm.val = itm.val.(int32) - 1
itm.val = val - 1
case uint:
if itm.val.(uint) > 0 {
itm.val = itm.val.(uint) - 1
if val > 0 {
itm.val = val - 1
} else {
return errors.New("item val is less than 0")
}
case uint32:
if itm.val.(uint32) > 0 {
itm.val = itm.val.(uint32) - 1
if val > 0 {
itm.val = val - 1
} else {
return errors.New("item val is less than 0")
}
case uint64:
if itm.val.(uint64) > 0 {
itm.val = itm.val.(uint64) - 1
if val > 0 {
itm.val = val - 1
} else {
return errors.New("item val is less than 0")
}
@ -203,40 +203,52 @@ func (bc *MemoryCache) StartAndGC(config string) error {
dur := time.Duration(cf["interval"]) * time.Second
bc.Every = cf["interval"]
bc.dur = dur
go bc.vaccuum()
go bc.vacuum()
return nil
}
// check expiration.
func (bc *MemoryCache) vaccuum() {
if bc.Every < 1 {
func (bc *MemoryCache) vacuum() {
bc.RLock()
every := bc.Every
bc.RUnlock()
if every < 1 {
return
}
for {
<-time.After(bc.dur)
bc.RLock()
if bc.items == nil {
bc.RUnlock()
return
}
for name := range bc.items {
bc.itemExpired(name)
bc.RUnlock()
if keys := bc.expiredKeys(); len(keys) != 0 {
bc.clearItems(keys)
}
}
}
// itemExpired returns true if an item is expired.
func (bc *MemoryCache) itemExpired(name string) bool {
// expiredKeys returns key list which are expired.
func (bc *MemoryCache) expiredKeys() (keys []string) {
bc.RLock()
defer bc.RUnlock()
for key, itm := range bc.items {
if itm.isExpire() {
keys = append(keys, key)
}
}
return
}
// clearItems removes all the items which key in keys.
func (bc *MemoryCache) clearItems(keys []string) {
bc.Lock()
defer bc.Unlock()
itm, ok := bc.items[name]
if !ok {
return true
for _, key := range keys {
delete(bc.items, key)
}
if itm.isExpire() {
delete(bc.items, name)
return true
}
return false
}
func init() {

134
cache/redis/redis.go vendored
View File

@ -14,9 +14,9 @@
// Package redis for cache provider
//
// depend on github.com/garyburd/redigo/redis
// depend on github.com/gomodule/redigo/redis
//
// go install github.com/garyburd/redigo/redis
// go install github.com/gomodule/redigo/redis
//
// Usage:
// import(
@ -32,12 +32,14 @@ package redis
import (
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
"github.com/garyburd/redigo/redis"
"github.com/gomodule/redigo/redis"
"github.com/astaxie/beego/cache"
"strings"
)
var (
@ -52,6 +54,10 @@ type Cache struct {
dbNum int
key string
password string
maxIdle int
//the timeout to a value less than the redis server's timeout.
timeout time.Duration
}
// NewRedisCache create new redis cache with default collection name.
@ -59,14 +65,23 @@ func NewRedisCache() cache.Cache {
return &Cache{key: DefaultKey}
}
// actually do the redis cmds
// actually do the redis cmds, args[0] must be the key name.
func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
if len(args) < 1 {
return nil, errors.New("missing required arguments")
}
args[0] = rc.associate(args[0])
c := rc.p.Get()
defer c.Close()
return c.Do(commandName, args...)
}
// associate with config key.
func (rc *Cache) associate(originKey interface{}) string {
return fmt.Sprintf("%s:%s", rc.key, originKey)
}
// Get cache from redis.
func (rc *Cache) Get(key string) interface{} {
if v, err := rc.do("GET", key); err == nil {
@ -77,57 +92,28 @@ func (rc *Cache) Get(key string) interface{} {
// GetMulti get cache from redis.
func (rc *Cache) GetMulti(keys []string) []interface{} {
size := len(keys)
var rv []interface{}
c := rc.p.Get()
defer c.Close()
var err error
var args []interface{}
for _, key := range keys {
err = c.Send("GET", key)
if err != nil {
goto ERROR
}
args = append(args, rc.associate(key))
}
if err = c.Flush(); err != nil {
goto ERROR
values, err := redis.Values(c.Do("MGET", args...))
if err != nil {
return nil
}
for i := 0; i < size; i++ {
if v, err := c.Receive(); err == nil {
rv = append(rv, v.([]byte))
} else {
rv = append(rv, err)
}
}
return rv
ERROR:
rv = rv[0:0]
for i := 0; i < size; i++ {
rv = append(rv, nil)
}
return rv
return values
}
// Put put cache to redis.
func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
var err error
if _, err = rc.do("SETEX", key, int64(timeout/time.Second), val); err != nil {
return err
}
if _, err = rc.do("HSET", rc.key, key, true); err != nil {
return err
}
_, err := rc.do("SETEX", key, int64(timeout/time.Second), val)
return err
}
// Delete delete cache in redis.
func (rc *Cache) Delete(key string) error {
var err error
if _, err = rc.do("DEL", key); err != nil {
return err
}
_, err = rc.do("HDEL", rc.key, key)
_, err := rc.do("DEL", key)
return err
}
@ -137,11 +123,6 @@ func (rc *Cache) IsExist(key string) bool {
if err != nil {
return false
}
if v == false {
if _, err = rc.do("HDEL", rc.key, key); err != nil {
return false
}
}
return v
}
@ -159,19 +140,49 @@ func (rc *Cache) Decr(key string) error {
// ClearAll clean all cache in redis. delete this redis collection.
func (rc *Cache) ClearAll() error {
cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key))
cachedKeys, err := rc.Scan(rc.key + ":*")
if err != nil {
return err
}
c := rc.p.Get()
defer c.Close()
for _, str := range cachedKeys {
if _, err = rc.do("DEL", str); err != nil {
if _, err = c.Do("DEL", str); err != nil {
return err
}
}
_, err = rc.do("DEL", rc.key)
return err
}
// Scan scan all keys matching the pattern. a better choice than `keys`
func (rc *Cache) Scan(pattern string) (keys []string, err error) {
c := rc.p.Get()
defer c.Close()
var (
cursor uint64 = 0 // start
result []interface{}
list []string
)
for {
result, err = redis.Values(c.Do("SCAN", cursor, "MATCH", pattern, "COUNT", 1024))
if err != nil {
return
}
list, err = redis.Strings(result[1], nil)
if err != nil {
return
}
keys = append(keys, list...)
cursor, err = redis.Uint64(result[0], nil)
if err != nil {
return
}
if cursor == 0 { // over
return
}
}
}
// StartAndGC start redis cache adapter.
// config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
// the cache item in redis are stored forever,
@ -186,16 +197,37 @@ func (rc *Cache) StartAndGC(config string) error {
if _, ok := cf["conn"]; !ok {
return errors.New("config has no conn key")
}
// Format redis://<password>@<host>:<port>
cf["conn"] = strings.Replace(cf["conn"], "redis://", "", 1)
if i := strings.Index(cf["conn"], "@"); i > -1 {
cf["password"] = cf["conn"][0:i]
cf["conn"] = cf["conn"][i+1:]
}
if _, ok := cf["dbNum"]; !ok {
cf["dbNum"] = "0"
}
if _, ok := cf["password"]; !ok {
cf["password"] = ""
}
if _, ok := cf["maxIdle"]; !ok {
cf["maxIdle"] = "3"
}
if _, ok := cf["timeout"]; !ok {
cf["timeout"] = "180s"
}
rc.key = cf["key"]
rc.conninfo = cf["conn"]
rc.dbNum, _ = strconv.Atoi(cf["dbNum"])
rc.password = cf["password"]
rc.maxIdle, _ = strconv.Atoi(cf["maxIdle"])
if v, err := time.ParseDuration(cf["timeout"]); err == nil {
rc.timeout = v
} else {
rc.timeout = 180 * time.Second
}
rc.connectInit()
@ -229,8 +261,8 @@ func (rc *Cache) connectInit() {
}
// initialize a new pool
rc.p = &redis.Pool{
MaxIdle: 3,
IdleTimeout: 180 * time.Second,
MaxIdle: rc.maxIdle,
IdleTimeout: rc.timeout,
Dial: dialFunc,
}
}

View File

@ -15,11 +15,12 @@
package redis
import (
"fmt"
"testing"
"time"
"github.com/astaxie/beego/cache"
"github.com/garyburd/redigo/redis"
"github.com/gomodule/redigo/redis"
)
func TestRedisCache(t *testing.T) {
@ -104,3 +105,40 @@ func TestRedisCache(t *testing.T) {
t.Error("clear all err")
}
}
func TestCache_Scan(t *testing.T) {
timeoutDuration := 10 * time.Second
// init
bm, err := cache.NewCache("redis", `{"conn": "127.0.0.1:6379"}`)
if err != nil {
t.Error("init err")
}
// insert all
for i := 0; i < 10000; i++ {
if err = bm.Put(fmt.Sprintf("astaxie%d", i), fmt.Sprintf("author%d", i), timeoutDuration); err != nil {
t.Error("set Error", err)
}
}
// scan all for the first time
keys, err := bm.(*Cache).Scan(DefaultKey + ":*")
if err != nil {
t.Error("scan Error", err)
}
if len(keys) != 10000 {
t.Error("scan all err")
}
// clear all
if err = bm.ClearAll(); err != nil {
t.Error("clear all err")
}
// scan all for the second time
keys, err = bm.(*Cache).Scan(DefaultKey + ":*")
if err != nil {
t.Error("scan Error", err)
}
if len(keys) != 0 {
t.Error("scan all err")
}
}

19
cache/ssdb/ssdb.go vendored
View File

@ -53,7 +53,7 @@ func (rc *Cache) GetMulti(keys []string) []interface{} {
resSize := len(res)
if err == nil {
for i := 1; i < resSize; i += 2 {
values = append(values, string(res[i+1]))
values = append(values, res[i+1])
}
return values
}
@ -71,10 +71,7 @@ func (rc *Cache) DelMulti(keys []string) error {
}
}
_, err := rc.conn.Do("multi_del", keys)
if err != nil {
return err
}
return nil
return err
}
// Put put value to memcache. only support string.
@ -113,10 +110,7 @@ func (rc *Cache) Delete(key string) error {
}
}
_, err := rc.conn.Del(key)
if err != nil {
return err
}
return nil
return err
}
// Incr increase counter.
@ -175,7 +169,7 @@ func (rc *Cache) ClearAll() error {
}
keys := []string{}
for i := 1; i < size; i += 2 {
keys = append(keys, string(resp[i]))
keys = append(keys, resp[i])
}
_, e := rc.conn.Do("multi_del", keys)
if e != nil {
@ -229,10 +223,7 @@ func (rc *Cache) connectInit() error {
}
var err error
rc.conn, err = ssdb.Connect(host, port)
if err != nil {
return err
}
return nil
return err
}
func init() {

101
config.go
View File

@ -49,22 +49,27 @@ type Config struct {
// Listen holds for http and https related config
type Listen struct {
Graceful bool // Graceful means use graceful module to start the server
ServerTimeOut int64
ListenTCP4 bool
EnableHTTP bool
HTTPAddr string
HTTPPort int
EnableHTTPS bool
HTTPSAddr string
HTTPSPort int
HTTPSCertFile string
HTTPSKeyFile string
EnableAdmin bool
AdminAddr string
AdminPort int
EnableFcgi bool
EnableStdIo bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
Graceful bool // Graceful means use graceful module to start the server
ServerTimeOut int64
ListenTCP4 bool
EnableHTTP bool
HTTPAddr string
HTTPPort int
AutoTLS bool
Domains []string
TLSCacheDir string
EnableHTTPS bool
EnableMutualHTTPS bool
HTTPSAddr string
HTTPSPort int
HTTPSCertFile string
HTTPSKeyFile string
TrustCaFile string
EnableAdmin bool
AdminAddr string
AdminPort int
EnableFcgi bool
EnableStdIo bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
}
// WebConfig holds web related config
@ -76,6 +81,8 @@ type WebConfig struct {
DirectoryIndex bool
StaticDir map[string]string
StaticExtensionsToGzip []string
StaticCacheFileSize int
StaticCacheFileNum int
TemplateLeft string
TemplateRight string
ViewsPath string
@ -96,16 +103,18 @@ type SessionConfig struct {
SessionAutoSetCookie bool
SessionDomain string
SessionDisableHTTPOnly bool // used to allow for cross domain cookies/javascript cookies.
SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headers
SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headers
SessionNameInHTTPHeader string
SessionEnableSidInURLQuery bool // enable get the sessionId from Url Query params
SessionEnableSidInURLQuery bool // enable get the sessionId from Url Query params
}
// LogConfig holds Log related config
type LogConfig struct {
AccessLogs bool
FileLineNum bool
Outputs map[string]string // Store Adaptor : config
AccessLogs bool
EnableStaticLogs bool //log static files requests default: false
AccessLogsFormat string //access log format: JSON_FORMAT, APACHE_FORMAT or empty string
FileLineNum bool
Outputs map[string]string // Store Adaptor : config
}
var (
@ -122,6 +131,8 @@ var (
appConfigPath string
// appConfigProvider is the provider for the config, default is ini
appConfigProvider = "ini"
// WorkPath is the absolute path to project root directory
WorkPath string
)
func init() {
@ -130,13 +141,17 @@ func init() {
if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
panic(err)
}
workPath, err := os.Getwd()
WorkPath, err = os.Getwd()
if err != nil {
panic(err)
}
appConfigPath = filepath.Join(workPath, "conf", "app.conf")
var filename = "app.conf"
if os.Getenv("BEEGO_RUNMODE") != "" {
filename = os.Getenv("BEEGO_RUNMODE") + ".app.conf"
}
appConfigPath = filepath.Join(WorkPath, "conf", filename)
if !utils.FileExists(appConfigPath) {
appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
appConfigPath = filepath.Join(AppPath, "conf", filename)
if !utils.FileExists(appConfigPath) {
AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
return
@ -175,13 +190,18 @@ func recoverPanic(ctx *context.Context) {
if BConfig.RunMode == DEV && BConfig.EnableErrorsRender {
showErr(err, ctx, stack)
}
if ctx.Output.Status != 0 {
ctx.ResponseWriter.WriteHeader(ctx.Output.Status)
} else {
ctx.ResponseWriter.WriteHeader(500)
}
}
}
func newBConfig() *Config {
return &Config{
AppName: "beego",
RunMode: DEV,
RunMode: PROD,
RouterCaseSensitive: true,
ServerName: "beegoServer:" + VERSION,
RecoverPanic: true,
@ -196,6 +216,9 @@ func newBConfig() *Config {
ServerTimeOut: 0,
ListenTCP4: false,
EnableHTTP: true,
AutoTLS: false,
Domains: []string{},
TLSCacheDir: ".",
HTTPAddr: "",
HTTPPort: 8080,
EnableHTTPS: false,
@ -217,6 +240,8 @@ func newBConfig() *Config {
DirectoryIndex: false,
StaticDir: map[string]string{"/static": "static"},
StaticExtensionsToGzip: []string{".css", ".js"},
StaticCacheFileSize: 1024 * 100,
StaticCacheFileNum: 1000,
TemplateLeft: "{{",
TemplateRight: "}}",
ViewsPath: "views",
@ -233,15 +258,17 @@ func newBConfig() *Config {
SessionCookieLifeTime: 0, //set cookie default is the browser life
SessionAutoSetCookie: true,
SessionDomain: "",
SessionEnableSidInHTTPHeader: false, // enable store/get the sessionId into/from http headers
SessionEnableSidInHTTPHeader: false, // enable store/get the sessionId into/from http headers
SessionNameInHTTPHeader: "Beegosessionid",
SessionEnableSidInURLQuery: false, // enable get the sessionId from Url Query params
SessionEnableSidInURLQuery: false, // enable get the sessionId from Url Query params
},
},
Log: LogConfig{
AccessLogs: false,
FileLineNum: true,
Outputs: map[string]string{"console": ""},
AccessLogs: false,
EnableStaticLogs: false,
AccessLogsFormat: "APACHE_FORMAT",
FileLineNum: true,
Outputs: map[string]string{"console": ""},
},
}
}
@ -296,6 +323,14 @@ func assignConfig(ac config.Configer) error {
}
}
if sfs, err := ac.Int("StaticCacheFileSize"); err == nil {
BConfig.WebConfig.StaticCacheFileSize = sfs
}
if sfn, err := ac.Int("StaticCacheFileNum"); err == nil {
BConfig.WebConfig.StaticCacheFileNum = sfn
}
if lo := ac.String("LogOutputs"); lo != "" {
// if lo is not nil or empty
// means user has set his own LogOutputs
@ -345,7 +380,7 @@ func assignSingleConfig(p interface{}, ac config.Configer) {
case reflect.String:
pf.SetString(ac.DefaultString(name, pf.String()))
case reflect.Int, reflect.Int64:
pf.SetInt(int64(ac.DefaultInt64(name, pf.Int())))
pf.SetInt(ac.DefaultInt64(name, pf.Int()))
case reflect.Bool:
pf.SetBool(ac.DefaultBool(name, pf.Bool()))
case reflect.Struct:
@ -387,9 +422,9 @@ func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, err
func (b *beegoAppConfig) Set(key, val string) error {
if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil {
return err
return b.innerConfig.Set(key, val)
}
return b.innerConfig.Set(key, val)
return nil
}
func (b *beegoAppConfig) String(key string) string {

View File

@ -150,12 +150,12 @@ func ExpandValueEnv(value string) (realValue string) {
}
key := ""
defalutV := ""
defaultV := ""
// value start with "${"
for i := 2; i < vLen; i++ {
if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') {
key = value[2:i]
defalutV = value[i+2 : vLen-1] // other string is default value.
defaultV = value[i+2 : vLen-1] // other string is default value.
break
} else if value[i] == '}' {
key = value[2:i]
@ -165,7 +165,7 @@ func ExpandValueEnv(value string) (realValue string) {
realValue = os.Getenv(key)
if realValue == "" {
realValue = defalutV
realValue = defaultV
}
return
@ -189,16 +189,16 @@ func ParseBool(val interface{}) (value bool, err error) {
return false, nil
}
case int8, int32, int64:
strV := fmt.Sprintf("%s", v)
strV := fmt.Sprintf("%d", v)
if strV == "1" {
return true, nil
} else if strV == "0" {
return false, nil
}
case float64:
if v == 1 {
if v == 1.0 {
return true, nil
} else if v == 0 {
} else if v == 0.0 {
return false, nil
}
}

2
config/env/env.go vendored
View File

@ -12,6 +12,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package env is used to parse environment.
package env
import (

View File

@ -126,7 +126,7 @@ func (c *fakeConfigContainer) SaveConfigFile(filename string) error {
var _ Configer = new(fakeConfigContainer)
// NewFakeConfig return a fake Congiger
// NewFakeConfig return a fake Configer
func NewFakeConfig() Configer {
return &fakeConfigContainer{
data: make(map[string]string),

View File

@ -21,6 +21,7 @@ import (
"io"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
@ -77,15 +78,37 @@ func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, e
}
}
section := defaultSection
tmpBuf := bytes.NewBuffer(nil)
for {
line, _, err := buf.ReadLine()
if err == io.EOF {
tmpBuf.Reset()
shouldBreak := false
for {
tmp, isPrefix, err := buf.ReadLine()
if err == io.EOF {
shouldBreak = true
break
}
//It might be a good idea to throw a error on all unknonw errors?
if _, ok := err.(*os.PathError); ok {
return nil, err
}
tmpBuf.Write(tmp)
if isPrefix {
continue
}
if !isPrefix {
break
}
}
if shouldBreak {
break
}
//It might be a good idea to throw a error on all unknonw errors?
if _, ok := err.(*os.PathError); ok {
return nil, err
}
line := tmpBuf.Bytes()
line = bytes.TrimSpace(line)
if bytes.Equal(line, bEmpty) {
continue
@ -184,10 +207,17 @@ func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, e
// ParseData parse ini the data
// When include other.conf,other.conf is either absolute directory
// or under beego in default temporary directory(/tmp/beego).
// or under beego in default temporary directory(/tmp/beego[-username]).
func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
dir := filepath.Join(os.TempDir(), "beego")
os.MkdirAll(dir, os.ModePerm)
dir := "beego"
currentUser, err := user.Current()
if err == nil {
dir = "beego-" + currentUser.Username
}
dir = filepath.Join(os.TempDir(), dir)
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return nil, err
}
return ini.parseData(dir, data)
}
@ -207,7 +237,7 @@ func (c *IniConfigContainer) Bool(key string) (bool, error) {
}
// DefaultBool returns the boolean value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
v, err := c.Bool(key)
if err != nil {
@ -222,7 +252,7 @@ func (c *IniConfigContainer) Int(key string) (int, error) {
}
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
v, err := c.Int(key)
if err != nil {
@ -237,7 +267,7 @@ func (c *IniConfigContainer) Int64(key string) (int64, error) {
}
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
v, err := c.Int64(key)
if err != nil {
@ -252,7 +282,7 @@ func (c *IniConfigContainer) Float(key string) (float64, error) {
}
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
v, err := c.Float(key)
if err != nil {
@ -267,7 +297,7 @@ func (c *IniConfigContainer) String(key string) string {
}
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *IniConfigContainer) DefaultString(key string, defaultval string) string {
v := c.String(key)
if v == "" {
@ -287,7 +317,7 @@ func (c *IniConfigContainer) Strings(key string) []string {
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string {
v := c.Strings(key)
if v == nil {
@ -306,7 +336,7 @@ func (c *IniConfigContainer) GetSection(section string) (map[string]string, erro
// SaveConfigFile save the config into file.
//
// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Funcation.
// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Function.
func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
// Write configuration file by filename.
f, err := os.Create(filename)
@ -317,7 +347,10 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
// Get section or key comments. Fixed #1607
getCommentStr := func(section, key string) string {
comment, ok := "", false
var (
comment string
ok bool
)
if len(key) == 0 {
comment, ok = c.sectionComment[section]
} else {
@ -397,11 +430,8 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
}
}
}
if _, err = buf.WriteTo(f); err != nil {
return err
}
return nil
_, err = buf.WriteTo(f)
return err
}
// Set writes a new value for key.
@ -416,7 +446,7 @@ func (c *IniConfigContainer) Set(key, value string) error {
var (
section, k string
sectionKey = strings.Split(key, "::")
sectionKey = strings.Split(strings.ToLower(key), "::")
)
if len(sectionKey) >= 2 {

View File

@ -181,7 +181,7 @@ name=mysql
cfgData := string(data)
datas := strings.Split(saveResult, "\n")
for _, line := range datas {
if strings.Contains(cfgData, line+"\n") == false {
if !strings.Contains(cfgData, line+"\n") {
t.Fatalf("different after save ini config file. need contains %q", line)
}
}

View File

@ -20,6 +20,7 @@ import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
)
@ -94,14 +95,16 @@ func (c *JSONConfigContainer) Int(key string) (int, error) {
if val != nil {
if v, ok := val.(float64); ok {
return int(v), nil
} else if v, ok := val.(string); ok {
return strconv.Atoi(v)
}
return 0, errors.New("not int value")
return 0, errors.New("not valid value")
}
return 0, errors.New("not exist key:" + key)
}
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int {
if v, err := c.Int(key); err == nil {
return v
@ -122,7 +125,7 @@ func (c *JSONConfigContainer) Int64(key string) (int64, error) {
}
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
if v, err := c.Int64(key); err == nil {
return v
@ -143,7 +146,7 @@ func (c *JSONConfigContainer) Float(key string) (float64, error) {
}
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
if v, err := c.Float(key); err == nil {
return v
@ -163,7 +166,7 @@ func (c *JSONConfigContainer) String(key string) string {
}
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *JSONConfigContainer) DefaultString(key string, defaultval string) string {
// TODO FIXME should not use "" to replace non existence
if v := c.String(key); v != "" {
@ -182,7 +185,7 @@ func (c *JSONConfigContainer) Strings(key string) []string {
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string {
if v := c.Strings(key); v != nil {
return v

View File

@ -216,7 +216,7 @@ func TestJson(t *testing.T) {
t.Error("unknown keys should return an error when expecting a Bool")
}
if !jsonconf.DefaultBool("unknow", true) {
if !jsonconf.DefaultBool("unknown", true) {
t.Error("unknown keys with default value wrong")
}
}

View File

@ -102,7 +102,7 @@ func (c *ConfigContainer) Int(key string) (int, error) {
}
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
v, err := c.Int(key)
if err != nil {
@ -117,7 +117,7 @@ func (c *ConfigContainer) Int64(key string) (int64, error) {
}
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
v, err := c.Int64(key)
if err != nil {
@ -133,7 +133,7 @@ func (c *ConfigContainer) Float(key string) (float64, error) {
}
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
v, err := c.Float(key)
if err != nil {
@ -151,7 +151,7 @@ func (c *ConfigContainer) String(key string) string {
}
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
v := c.String(key)
if v == "" {
@ -170,7 +170,7 @@ func (c *ConfigContainer) Strings(key string) []string {
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
v := c.Strings(key)
if v == nil {

View File

@ -97,7 +97,7 @@ func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
}
}
data, err := goyaml2.Read(bytes.NewBuffer(buf))
data, err := goyaml2.Read(bytes.NewReader(buf))
if err != nil {
log.Println("Goyaml2 ERR>", string(buf), err)
return
@ -119,7 +119,7 @@ func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
// ConfigContainer A Config represents the yaml configuration.
type ConfigContainer struct {
data map[string]interface{}
sync.Mutex
sync.RWMutex
}
// Bool returns the boolean value for a given key.
@ -154,7 +154,7 @@ func (c *ConfigContainer) Int(key string) (int, error) {
}
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
v, err := c.Int(key)
if err != nil {
@ -174,7 +174,7 @@ func (c *ConfigContainer) Int64(key string) (int64, error) {
}
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
v, err := c.Int64(key)
if err != nil {
@ -198,7 +198,7 @@ func (c *ConfigContainer) Float(key string) (float64, error) {
}
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
v, err := c.Float(key)
if err != nil {
@ -218,7 +218,7 @@ func (c *ConfigContainer) String(key string) string {
}
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
v := c.String(key)
if v == "" {
@ -237,7 +237,7 @@ func (c *ConfigContainer) Strings(key string) []string {
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
// if err != nil return defaultval
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
v := c.Strings(key)
if v == nil {
@ -285,9 +285,28 @@ func (c *ConfigContainer) getData(key string) (interface{}, error) {
if len(key) == 0 {
return nil, errors.New("key is empty")
}
c.RLock()
defer c.RUnlock()
if v, ok := c.data[key]; ok {
return v, nil
keys := strings.Split(key, ".")
tmpData := c.data
for idx, k := range keys {
if v, ok := tmpData[k]; ok {
switch v.(type) {
case map[string]interface{}:
{
tmpData = v.(map[string]interface{})
if idx == len(keys) - 1 {
return tmpData, nil
}
}
default:
{
return v, nil
}
}
}
}
return nil, fmt.Errorf("not exist key %q", key)
}

View File

@ -48,15 +48,15 @@ func TestAssignConfig_02(t *testing.T) {
_BConfig := &Config{}
bs, _ := json.Marshal(newBConfig())
jsonMap := map[string]interface{}{}
jsonMap := M{}
json.Unmarshal(bs, &jsonMap)
configMap := map[string]interface{}{}
configMap := M{}
for k, v := range jsonMap {
if reflect.TypeOf(v).Kind() == reflect.Map {
for k1, v1 := range v.(map[string]interface{}) {
for k1, v1 := range v.(M) {
if reflect.TypeOf(v1).Kind() == reflect.Map {
for k2, v2 := range v1.(map[string]interface{}) {
for k2, v2 := range v1.(M) {
configMap[k2] = v2
}
} else {
@ -75,7 +75,7 @@ func TestAssignConfig_02(t *testing.T) {
jcf := &config.JSONConfig{}
bs, _ = json.Marshal(configMap)
ac, _ := jcf.ParseData([]byte(bs))
ac, _ := jcf.ParseData(bs)
for _, i := range []interface{}{_BConfig, &_BConfig.Listen, &_BConfig.WebConfig, &_BConfig.Log, &_BConfig.WebConfig.Session} {
assignSingleConfig(i, ac)
@ -115,6 +115,8 @@ func TestAssignConfig_03(t *testing.T) {
ac.Set("RunMode", "online")
ac.Set("StaticDir", "download:down download2:down2")
ac.Set("StaticExtensionsToGzip", ".css,.js,.html,.jpg,.png")
ac.Set("StaticCacheFileSize", "87456")
ac.Set("StaticCacheFileNum", "1254")
assignConfig(ac)
t.Logf("%#v", BConfig)
@ -132,6 +134,12 @@ func TestAssignConfig_03(t *testing.T) {
if BConfig.WebConfig.StaticDir["/download2"] != "down2" {
t.FailNow()
}
if BConfig.WebConfig.StaticCacheFileSize != 87456 {
t.FailNow()
}
if BConfig.WebConfig.StaticCacheFileNum != 1254 {
t.FailNow()
}
if len(BConfig.WebConfig.StaticExtensionsToGzip) != 5 {
t.FailNow()
}

View File

@ -39,6 +39,7 @@ var (
getMethodOnly bool
)
// InitGzip init the gzipcompress
func InitGzip(minLength, compressLevel int, methods []string) {
if minLength >= 0 {
gzipMinLength = minLength

View File

@ -25,7 +25,7 @@ package context
import (
"bufio"
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
@ -38,6 +38,14 @@ import (
"github.com/astaxie/beego/utils"
)
//commonly used mime-types
const (
ApplicationJSON = "application/json"
ApplicationXML = "application/xml"
ApplicationYAML = "application/x-yaml"
TextXML = "text/xml"
)
// NewContext return the Context with Input and Output
func NewContext() *Context {
return &Context{
@ -115,7 +123,7 @@ func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) {
timestamp := parts[1]
sig := parts[2]
h := hmac.New(sha1.New, []byte(Secret))
h := hmac.New(sha256.New, []byte(Secret))
fmt.Fprintf(h, "%s%s", vs, timestamp)
if fmt.Sprintf("%02x", h.Sum(nil)) != sig {
@ -129,7 +137,7 @@ func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) {
func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) {
vs := base64.URLEncoding.EncodeToString([]byte(value))
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
h := hmac.New(sha1.New, []byte(Secret))
h := hmac.New(sha256.New, []byte(Secret))
fmt.Fprintf(h, "%s%s", vs, timestamp)
sig := fmt.Sprintf("%02x", h.Sum(nil))
cookie := strings.Join([]string{vs, timestamp, sig}, "|")
@ -161,22 +169,39 @@ func (ctx *Context) CheckXSRFCookie() bool {
token = ctx.Request.Header.Get("X-Csrftoken")
}
if token == "" {
ctx.Abort(403, "'_xsrf' argument missing from POST")
ctx.Abort(422, "422")
return false
}
if ctx._xsrfToken != token {
ctx.Abort(403, "XSRF cookie does not match POST argument")
ctx.Abort(417, "417")
return false
}
return true
}
// RenderMethodResult renders the return value of a controller method to the output
func (ctx *Context) RenderMethodResult(result interface{}) {
if result != nil {
renderer, ok := result.(Renderer)
if !ok {
err, ok := result.(error)
if ok {
renderer = errorRenderer(err)
} else {
renderer = jsonRenderer(result)
}
}
renderer.Render(ctx)
}
}
//Response is a wrapper for the http.ResponseWriter
//started set to true if response was written to then don't execute other handler
type Response struct {
http.ResponseWriter
Started bool
Status int
Elapsed time.Duration
}
func (r *Response) reset(rw http.ResponseWriter) {
@ -228,3 +253,11 @@ func (r *Response) CloseNotify() <-chan bool {
}
return nil
}
// Pusher http.Pusher
func (r *Response) Pusher() (pusher http.Pusher) {
if pusher, ok := r.ResponseWriter.(http.Pusher); ok {
return pusher
}
return nil
}

View File

@ -16,14 +16,18 @@ package context
import (
"bytes"
"compress/gzip"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"github.com/astaxie/beego/session"
)
@ -34,6 +38,7 @@ var (
acceptsHTMLRegex = regexp.MustCompile(`(text/html|application/xhtml\+xml)(?:,|$)`)
acceptsXMLRegex = regexp.MustCompile(`(application/xml|text/xml)(?:,|$)`)
acceptsJSONRegex = regexp.MustCompile(`(application/json)(?:,|$)`)
acceptsYAMLRegex = regexp.MustCompile(`(application/x-yaml)(?:,|$)`)
maxParam = 50
)
@ -45,6 +50,7 @@ type BeegoInput struct {
pnames []string
pvalues []string
data map[interface{}]interface{} // store some values in this context when calling context in filter or controller.
dataLock sync.RWMutex
RequestBody []byte
RunMethod string
RunController reflect.Type
@ -65,7 +71,9 @@ func (input *BeegoInput) Reset(ctx *Context) {
input.CruSession = nil
input.pnames = input.pnames[:0]
input.pvalues = input.pvalues[:0]
input.dataLock.Lock()
input.data = nil
input.dataLock.Unlock()
input.RequestBody = []byte{}
}
@ -81,7 +89,7 @@ func (input *BeegoInput) URI() string {
// URL returns request url path (without query string, fragment).
func (input *BeegoInput) URL() string {
return input.Context.Request.URL.Path
return input.Context.Request.URL.EscapedPath()
}
// Site returns base site url as scheme://domain type.
@ -113,9 +121,8 @@ func (input *BeegoInput) Domain() string {
// if no host info in request, return localhost.
func (input *BeegoInput) Host() string {
if input.Context.Request.Host != "" {
hostParts := strings.Split(input.Context.Request.Host, ":")
if len(hostParts) > 0 {
return hostParts[0]
if hostPart, _, err := net.SplitHostPort(input.Context.Request.Host); err == nil {
return hostPart
}
return input.Context.Request.Host
}
@ -202,22 +209,27 @@ func (input *BeegoInput) AcceptsJSON() bool {
return acceptsJSONRegex.MatchString(input.Header("Accept"))
}
// AcceptsYAML Checks if request accepts json response
func (input *BeegoInput) AcceptsYAML() bool {
return acceptsYAMLRegex.MatchString(input.Header("Accept"))
}
// IP returns request client ip.
// if in proxy, return first proxy id.
// if error, return 127.0.0.1.
// if error, return RemoteAddr.
func (input *BeegoInput) IP() string {
ips := input.Proxy()
if len(ips) > 0 && ips[0] != "" {
rip := strings.Split(ips[0], ":")
return rip[0]
}
ip := strings.Split(input.Context.Request.RemoteAddr, ":")
if len(ip) > 0 {
if ip[0] != "[" {
return ip[0]
rip, _, err := net.SplitHostPort(ips[0])
if err != nil {
rip = ips[0]
}
return rip
}
return "127.0.0.1"
if ip, _, err := net.SplitHostPort(input.Context.Request.RemoteAddr); err == nil {
return ip
}
return input.Context.Request.RemoteAddr
}
// Proxy returns proxy client ips slice.
@ -251,9 +263,8 @@ func (input *BeegoInput) SubDomains() string {
// Port returns request client port.
// when error or empty, return 80.
func (input *BeegoInput) Port() int {
parts := strings.Split(input.Context.Request.Host, ":")
if len(parts) == 2 {
port, _ := strconv.Atoi(parts[1])
if _, portPart, err := net.SplitHostPort(input.Context.Request.Host); err == nil {
port, _ := strconv.Atoi(portPart)
return port
}
return 80
@ -273,6 +284,11 @@ func (input *BeegoInput) ParamsLen() int {
func (input *BeegoInput) Param(key string) string {
for i, v := range input.pnames {
if v == key && i <= len(input.pvalues) {
// we cannot use url.PathEscape(input.pvalues[i])
// for example, if the value is /a/b
// after url.PathEscape(input.pvalues[i]), the value is %2Fa%2Fb
// However, the value is used in ControllerRegister.ServeHTTP
// and split by "/", so function crash...
return input.pvalues[i]
}
}
@ -349,17 +365,30 @@ func (input *BeegoInput) CopyBody(MaxMemory int64) []byte {
if input.Context.Request.Body == nil {
return []byte{}
}
var requestbody []byte
safe := &io.LimitedReader{R: input.Context.Request.Body, N: MaxMemory}
requestbody, _ := ioutil.ReadAll(safe)
if input.Header("Content-Encoding") == "gzip" {
reader, err := gzip.NewReader(safe)
if err != nil {
return nil
}
requestbody, _ = ioutil.ReadAll(reader)
} else {
requestbody, _ = ioutil.ReadAll(safe)
}
input.Context.Request.Body.Close()
bf := bytes.NewBuffer(requestbody)
input.Context.Request.Body = ioutil.NopCloser(bf)
input.Context.Request.Body = http.MaxBytesReader(input.Context.ResponseWriter, ioutil.NopCloser(bf), MaxMemory)
input.RequestBody = requestbody
return requestbody
}
// Data return the implicit data in the input
func (input *BeegoInput) Data() map[interface{}]interface{} {
input.dataLock.Lock()
defer input.dataLock.Unlock()
if input.data == nil {
input.data = make(map[interface{}]interface{})
}
@ -368,6 +397,8 @@ func (input *BeegoInput) Data() map[interface{}]interface{} {
// GetData returns the stored data in this context.
func (input *BeegoInput) GetData(key interface{}) interface{} {
input.dataLock.Lock()
defer input.dataLock.Unlock()
if v, ok := input.data[key]; ok {
return v
}
@ -377,6 +408,8 @@ func (input *BeegoInput) GetData(key interface{}) interface{} {
// SetData stores data with given key in this context.
// This data are only available in this context.
func (input *BeegoInput) SetData(key, val interface{}) {
input.dataLock.Lock()
defer input.dataLock.Unlock()
if input.data == nil {
input.data = make(map[interface{}]interface{})
}

View File

@ -73,8 +73,8 @@ func TestBind(t *testing.T) {
{"/?human.ID=888&human.Nick=astaxie&human.Ms=true&human[Pwd]=pass", []testItem{{"human", Human{}, Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass"}}}},
{"/?human[0].ID=888&human[0].Nick=astaxie&human[0].Ms=true&human[0][Pwd]=pass01&human[1].ID=999&human[1].Nick=ysqi&human[1].Ms=On&human[1].Pwd=pass02",
[]testItem{{"human", []Human{}, []Human{
Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass01"},
Human{ID: 999, Nick: "ysqi", Ms: true, Pwd: "pass02"},
{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass01"},
{ID: 999, Nick: "ysqi", Ms: true, Pwd: "pass02"},
}}}},
{

View File

@ -30,6 +30,8 @@ import (
"strconv"
"strings"
"time"
yaml "gopkg.in/yaml.v2"
)
// BeegoOutput does work for sending response header.
@ -168,9 +170,22 @@ func sanitizeValue(v string) string {
return cookieValueSanitizer.Replace(v)
}
func jsonRenderer(value interface{}) Renderer {
return rendererFunc(func(ctx *Context) {
ctx.Output.JSON(value, false, false)
})
}
func errorRenderer(err error) Renderer {
return rendererFunc(func(ctx *Context) {
ctx.Output.SetStatus(500)
ctx.Output.Body([]byte(err.Error()))
})
}
// JSON writes json to response body.
// if coding is true, it converts utf-8 to \u0000 type.
func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) error {
// if encoding is true, it converts utf-8 to \u0000 type.
func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding bool) error {
output.Header("Content-Type", "application/json; charset=utf-8")
var content []byte
var err error
@ -183,12 +198,25 @@ func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) e
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
return err
}
if coding {
if encoding {
content = []byte(stringsToJSON(string(content)))
}
return output.Body(content)
}
// YAML writes yaml to response body.
func (output *BeegoOutput) YAML(data interface{}) error {
output.Header("Content-Type", "application/x-yaml; charset=utf-8")
var content []byte
var err error
content, err = yaml.Marshal(data)
if err != nil {
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
return err
}
return output.Body(content)
}
// JSONP writes jsonp to response body.
func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error {
output.Header("Content-Type", "application/javascript; charset=utf-8")
@ -232,6 +260,19 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error {
return output.Body(content)
}
// ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header
func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) {
accept := output.Context.Input.Header("Accept")
switch accept {
case ApplicationYAML:
output.YAML(data)
case ApplicationXML, TextXML:
output.XML(data, hasIndent)
default:
output.JSON(data, hasIndent, len(hasEncode) > 0 && hasEncode[0])
}
}
// Download forces response for download file.
// it prepares the download response header automatically.
func (output *BeegoOutput) Download(file string, filename ...string) {
@ -247,7 +288,20 @@ func (output *BeegoOutput) Download(file string, filename ...string) {
} else {
fName = filepath.Base(file)
}
output.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(fName))
//https://tools.ietf.org/html/rfc6266#section-4.3
fn := url.PathEscape(fName)
if fName == fn {
fn = "filename=" + fn
} else {
/**
The parameters "filename" and "filename*" differ only in that
"filename*" uses the encoding defined in [RFC5987], allowing the use
of characters not present in the ISO-8859-1 character set
([ISO-8859-1]).
*/
fn = "filename=" + fName + "; filename*=utf-8''" + fn
}
output.Header("Content-Disposition", "attachment; "+fn)
output.Header("Content-Description", "File Transfer")
output.Header("Content-Type", "application/octet-stream")
output.Header("Content-Transfer-Encoding", "binary")
@ -312,13 +366,13 @@ func (output *BeegoOutput) IsForbidden() bool {
}
// IsNotFound returns boolean of this request is not found.
// HTTP 404 means forbidden.
// HTTP 404 means not found.
func (output *BeegoOutput) IsNotFound() bool {
return output.Status == 404
}
// IsClientError returns boolean of this request client sends error data.
// HTTP 4xx means forbidden.
// HTTP 4xx means client error.
func (output *BeegoOutput) IsClientError() bool {
return output.Status >= 400 && output.Status < 500
}
@ -330,14 +384,18 @@ func (output *BeegoOutput) IsServerError() bool {
}
func stringsToJSON(str string) string {
rs := []rune(str)
var jsons bytes.Buffer
for _, r := range rs {
for _, r := range str {
rint := int(r)
if rint < 128 {
jsons.WriteRune(r)
} else {
jsons.WriteString("\\u")
if rint < 0x100 {
jsons.WriteString("00")
} else if rint < 0x1000 {
jsons.WriteString("0")
}
jsons.WriteString(strconv.FormatInt(int64(rint), 16))
}
}

78
context/param/conv.go Normal file
View File

@ -0,0 +1,78 @@
package param
import (
"fmt"
"reflect"
beecontext "github.com/astaxie/beego/context"
"github.com/astaxie/beego/logs"
)
// ConvertParams converts http method params to values that will be passed to the method controller as arguments
func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) {
result = make([]reflect.Value, 0, len(methodParams))
for i := 0; i < len(methodParams); i++ {
reflectValue := convertParam(methodParams[i], methodType.In(i), ctx)
result = append(result, reflectValue)
}
return
}
func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) {
paramValue := getParamValue(param, ctx)
if paramValue == "" {
if param.required {
ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name))
} else {
paramValue = param.defaultValue
}
}
reflectValue, err := parseValue(param, paramValue, paramType)
if err != nil {
logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err))
ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType))
}
return reflectValue
}
func getParamValue(param *MethodParam, ctx *beecontext.Context) string {
switch param.in {
case body:
return string(ctx.Input.RequestBody)
case header:
return ctx.Input.Header(param.name)
case path:
return ctx.Input.Query(":" + param.name)
default:
return ctx.Input.Query(param.name)
}
}
func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) {
if paramValue == "" {
return reflect.Zero(paramType), nil
}
parser := getParser(param, paramType)
value, err := parser.parse(paramValue, paramType)
if err != nil {
return result, err
}
return safeConvert(reflect.ValueOf(value), paramType)
}
func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
}
}()
result = value.Convert(t)
return
}

View File

@ -0,0 +1,69 @@
package param
import (
"fmt"
"strings"
)
//MethodParam keeps param information to be auto passed to controller methods
type MethodParam struct {
name string
in paramType
required bool
defaultValue string
}
type paramType byte
const (
param paramType = iota
path
body
header
)
//New creates a new MethodParam with name and specific options
func New(name string, opts ...MethodParamOption) *MethodParam {
return newParam(name, nil, opts)
}
func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) {
param = &MethodParam{name: name}
for _, option := range opts {
option(param)
}
return
}
//Make creates an array of MethodParmas or an empty array
func Make(list ...*MethodParam) []*MethodParam {
if len(list) > 0 {
return list
}
return nil
}
func (mp *MethodParam) String() string {
options := []string{}
result := "param.New(\"" + mp.name + "\""
if mp.required {
options = append(options, "param.IsRequired")
}
switch mp.in {
case path:
options = append(options, "param.InPath")
case body:
options = append(options, "param.InBody")
case header:
options = append(options, "param.InHeader")
}
if mp.defaultValue != "" {
options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defaultValue))
}
if len(options) > 0 {
result += ", "
}
result += strings.Join(options, ", ")
result += ")"
return result
}

37
context/param/options.go Normal file
View File

@ -0,0 +1,37 @@
package param
import (
"fmt"
)
// MethodParamOption defines a func which apply options on a MethodParam
type MethodParamOption func(*MethodParam)
// IsRequired indicates that this param is required and can not be omitted from the http request
var IsRequired MethodParamOption = func(p *MethodParam) {
p.required = true
}
// InHeader indicates that this param is passed via an http header
var InHeader MethodParamOption = func(p *MethodParam) {
p.in = header
}
// InPath indicates that this param is part of the URL path
var InPath MethodParamOption = func(p *MethodParam) {
p.in = path
}
// InBody indicates that this param is passed as an http request body
var InBody MethodParamOption = func(p *MethodParam) {
p.in = body
}
// Default provides a default value for the http param
func Default(defaultValue interface{}) MethodParamOption {
return func(p *MethodParam) {
if defaultValue != nil {
p.defaultValue = fmt.Sprint(defaultValue)
}
}
}

149
context/param/parsers.go Normal file
View File

@ -0,0 +1,149 @@
package param
import (
"encoding/json"
"reflect"
"strconv"
"strings"
"time"
)
type paramParser interface {
parse(value string, toType reflect.Type) (interface{}, error)
}
func getParser(param *MethodParam, t reflect.Type) paramParser {
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return intParser{}
case reflect.Slice:
if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string
return stringParser{}
}
if param.in == body {
return jsonParser{}
}
elemParser := getParser(param, t.Elem())
if elemParser == (jsonParser{}) {
return elemParser
}
return sliceParser(elemParser)
case reflect.Bool:
return boolParser{}
case reflect.String:
return stringParser{}
case reflect.Float32, reflect.Float64:
return floatParser{}
case reflect.Ptr:
elemParser := getParser(param, t.Elem())
if elemParser == (jsonParser{}) {
return elemParser
}
return ptrParser(elemParser)
default:
if t.PkgPath() == "time" && t.Name() == "Time" {
return timeParser{}
}
return jsonParser{}
}
}
type parserFunc func(value string, toType reflect.Type) (interface{}, error)
func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) {
return f(value, toType)
}
type boolParser struct {
}
func (p boolParser) parse(value string, toType reflect.Type) (interface{}, error) {
return strconv.ParseBool(value)
}
type stringParser struct {
}
func (p stringParser) parse(value string, toType reflect.Type) (interface{}, error) {
return value, nil
}
type intParser struct {
}
func (p intParser) parse(value string, toType reflect.Type) (interface{}, error) {
return strconv.Atoi(value)
}
type floatParser struct {
}
func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) {
if toType.Kind() == reflect.Float32 {
res, err := strconv.ParseFloat(value, 32)
if err != nil {
return nil, err
}
return float32(res), nil
}
return strconv.ParseFloat(value, 64)
}
type timeParser struct {
}
func (p timeParser) parse(value string, toType reflect.Type) (result interface{}, err error) {
result, err = time.Parse(time.RFC3339, value)
if err != nil {
result, err = time.Parse("2006-01-02", value)
}
return
}
type jsonParser struct {
}
func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error) {
pResult := reflect.New(toType)
v := pResult.Interface()
err := json.Unmarshal([]byte(value), v)
if err != nil {
return nil, err
}
return pResult.Elem().Interface(), nil
}
func sliceParser(elemParser paramParser) paramParser {
return parserFunc(func(value string, toType reflect.Type) (interface{}, error) {
values := strings.Split(value, ",")
result := reflect.MakeSlice(toType, 0, len(values))
elemType := toType.Elem()
for _, v := range values {
parsedValue, err := elemParser.parse(v, elemType)
if err != nil {
return nil, err
}
result = reflect.Append(result, reflect.ValueOf(parsedValue))
}
return result.Interface(), nil
})
}
func ptrParser(elemParser paramParser) paramParser {
return parserFunc(func(value string, toType reflect.Type) (interface{}, error) {
parsedValue, err := elemParser.parse(value, toType.Elem())
if err != nil {
return nil, err
}
newValPtr := reflect.New(toType.Elem())
newVal := reflect.Indirect(newValPtr)
convertedVal, err := safeConvert(reflect.ValueOf(parsedValue), toType.Elem())
if err != nil {
return nil, err
}
newVal.Set(convertedVal)
return newValPtr.Interface(), nil
})
}

View File

@ -0,0 +1,84 @@
package param
import "testing"
import "reflect"
import "time"
type testDefinition struct {
strValue string
expectedValue interface{}
expectedParser paramParser
}
func Test_Parsers(t *testing.T) {
//ints
checkParser(testDefinition{"1", 1, intParser{}}, t)
checkParser(testDefinition{"-1", int64(-1), intParser{}}, t)
checkParser(testDefinition{"1", uint64(1), intParser{}}, t)
//floats
checkParser(testDefinition{"1.0", float32(1.0), floatParser{}}, t)
checkParser(testDefinition{"-1.0", float64(-1.0), floatParser{}}, t)
//strings
checkParser(testDefinition{"AB", "AB", stringParser{}}, t)
checkParser(testDefinition{"AB", []byte{65, 66}, stringParser{}}, t)
//bools
checkParser(testDefinition{"true", true, boolParser{}}, t)
checkParser(testDefinition{"0", false, boolParser{}}, t)
//timeParser
checkParser(testDefinition{"2017-05-30T13:54:53Z", time.Date(2017, 5, 30, 13, 54, 53, 0, time.UTC), timeParser{}}, t)
checkParser(testDefinition{"2017-05-30", time.Date(2017, 5, 30, 0, 0, 0, 0, time.UTC), timeParser{}}, t)
//json
checkParser(testDefinition{`{"X": 5, "Y":"Z"}`, struct {
X int
Y string
}{5, "Z"}, jsonParser{}}, t)
//slice in query is parsed as comma delimited
checkParser(testDefinition{`1,2`, []int{1, 2}, sliceParser(intParser{})}, t)
//slice in body is parsed as json
checkParser(testDefinition{`["a","b"]`, []string{"a", "b"}, jsonParser{}}, t, MethodParam{in: body})
//pointers
var someInt = 1
checkParser(testDefinition{`1`, &someInt, ptrParser(intParser{})}, t)
var someStruct = struct{ X int }{5}
checkParser(testDefinition{`{"X": 5}`, &someStruct, jsonParser{}}, t)
}
func checkParser(def testDefinition, t *testing.T, methodParam ...MethodParam) {
toType := reflect.TypeOf(def.expectedValue)
var mp MethodParam
if len(methodParam) == 0 {
mp = MethodParam{}
} else {
mp = methodParam[0]
}
parser := getParser(&mp, toType)
if reflect.TypeOf(parser) != reflect.TypeOf(def.expectedParser) {
t.Errorf("Invalid parser for value %v. Expected: %v, actual: %v", def.strValue, reflect.TypeOf(def.expectedParser).Name(), reflect.TypeOf(parser).Name())
return
}
result, err := parser.parse(def.strValue, toType)
if err != nil {
t.Errorf("Parsing error for value %v. Expected result: %v, error: %v", def.strValue, def.expectedValue, err)
return
}
convResult, err := safeConvert(reflect.ValueOf(result), toType)
if err != nil {
t.Errorf("Conversion error for %v. from value: %v, toType: %v, error: %v", def.strValue, result, toType, err)
return
}
if !reflect.DeepEqual(convResult.Interface(), def.expectedValue) {
t.Errorf("Parsing error for value %v. Expected result: %v, actual: %v", def.strValue, def.expectedValue, result)
}
}

12
context/renderer.go Normal file
View File

@ -0,0 +1,12 @@
package context
// Renderer defines an http response renderer
type Renderer interface {
Render(ctx *Context)
}
type rendererFunc func(ctx *Context)
func (f rendererFunc) Render(ctx *Context) {
f(ctx)
}

27
context/response.go Normal file
View File

@ -0,0 +1,27 @@
package context
import (
"strconv"
"net/http"
)
const (
//BadRequest indicates http error 400
BadRequest StatusCode = http.StatusBadRequest
//NotFound indicates http error 404
NotFound StatusCode = http.StatusNotFound
)
// StatusCode sets the http response status code
type StatusCode int
func (s StatusCode) Error() string {
return strconv.Itoa(int(s))
}
// Render sets the http status code
func (s StatusCode) Render(ctx *Context) {
ctx.Output.SetStatus(int(s))
}

View File

@ -17,6 +17,7 @@ package beego
import (
"bytes"
"errors"
"fmt"
"html/template"
"io"
"mime/multipart"
@ -28,31 +29,60 @@ import (
"strings"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/context/param"
"github.com/astaxie/beego/session"
)
//commonly used mime-types
const (
applicationJSON = "application/json"
applicationXML = "application/xml"
textXML = "text/xml"
)
var (
// ErrAbort custom error when user stop request handler manually.
ErrAbort = errors.New("User stop run")
ErrAbort = errors.New("user stop run")
// GlobalControllerRouter store comments with controller. pkgpath+controller:comments
GlobalControllerRouter = make(map[string][]ControllerComments)
)
// ControllerFilter store the filter for controller
type ControllerFilter struct {
Pattern string
Pos int
Filter FilterFunc
ReturnOnOutput bool
ResetParams bool
}
// ControllerFilterComments store the comment for controller level filter
type ControllerFilterComments struct {
Pattern string
Pos int
Filter string // NOQA
ReturnOnOutput bool
ResetParams bool
}
// ControllerImportComments store the import comment for controller needed
type ControllerImportComments struct {
ImportPath string
ImportAlias string
}
// ControllerComments store the comment for the controller method
type ControllerComments struct {
Method string
Router string
Filters []*ControllerFilter
ImportComments []*ControllerImportComments
FilterComments []*ControllerFilterComments
AllowHTTPMethods []string
Params []map[string]string
MethodParams []*param.MethodParam
}
// ControllerCommentsSlice implements the sort interface
type ControllerCommentsSlice []ControllerComments
func (p ControllerCommentsSlice) Len() int { return len(p) }
func (p ControllerCommentsSlice) Less(i, j int) bool { return p[i].Router < p[j].Router }
func (p ControllerCommentsSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Controller defines some basic http request handler operations, such as
// http context, template and view, session and xsrf.
type Controller struct {
@ -64,7 +94,6 @@ type Controller struct {
controllerName string
actionName string
methodMapping map[string]func() //method:routertree
gotofunc string
AppController interface{}
// template data
@ -96,6 +125,7 @@ type ControllerInterface interface {
Head()
Patch()
Options()
Trace()
Finish()
Render() error
XSRFToken() string
@ -127,37 +157,59 @@ func (c *Controller) Finish() {}
// Get adds a request function to handle GET request.
func (c *Controller) Get() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Post adds a request function to handle POST request.
func (c *Controller) Post() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Delete adds a request function to handle DELETE request.
func (c *Controller) Delete() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Put adds a request function to handle PUT request.
func (c *Controller) Put() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Head adds a request function to handle HEAD request.
func (c *Controller) Head() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Patch adds a request function to handle PATCH request.
func (c *Controller) Patch() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Options adds a request function to handle OPTIONS request.
func (c *Controller) Options() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
// Trace adds a request function to handle Trace request.
// this method SHOULD NOT be overridden.
// https://tools.ietf.org/html/rfc7231#section-4.3.8
// The TRACE method requests a remote, application-level loop-back of
// the request message. The final recipient of the request SHOULD
// reflect the message received, excluding some fields described below,
// back to the client as the message body of a 200 (OK) response with a
// Content-Type of "message/http" (Section 8.3.1 of [RFC7230]).
func (c *Controller) Trace() {
ts := func(h http.Header) (hs string) {
for k, v := range h {
hs += fmt.Sprintf("\r\n%s: %s", k, v)
}
return
}
hs := fmt.Sprintf("\r\nTRACE %s %s%s\r\n", c.Ctx.Request.RequestURI, c.Ctx.Request.Proto, ts(c.Ctx.Request.Header))
c.Ctx.Output.Header("Content-Type", "message/http")
c.Ctx.Output.Header("Content-Length", fmt.Sprint(len(hs)))
c.Ctx.Output.Header("Cache-Control", "no-cache, no-store, must-revalidate")
c.Ctx.WriteString(hs)
}
// HandlerFunc call function with the name
@ -223,7 +275,7 @@ func (c *Controller) RenderBytes() ([]byte, error) {
}
buf.Reset()
ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath() ,c.Data)
ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data)
}
return buf.Bytes(), err
}
@ -249,7 +301,7 @@ func (c *Controller) renderTemplate() (bytes.Buffer, error) {
}
}
}
BuildTemplate(c.viewPath() , buildFiles...)
BuildTemplate(c.viewPath(), buildFiles...)
}
return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data)
}
@ -263,9 +315,23 @@ func (c *Controller) viewPath() string {
// Redirect sends the redirection response to url with status code.
func (c *Controller) Redirect(url string, code int) {
LogAccess(c.Ctx, nil, code)
c.Ctx.Redirect(code, url)
}
// SetData set the data depending on the accepted
func (c *Controller) SetData(data interface{}) {
accept := c.Ctx.Input.Header("Accept")
switch accept {
case context.ApplicationYAML:
c.Data["yaml"] = data
case context.ApplicationXML, context.TextXML:
c.Data["xml"] = data
default:
c.Data["json"] = data
}
}
// Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
func (c *Controller) Abort(code string) {
status, err := strconv.Atoi(code)
@ -308,47 +374,35 @@ func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
// ServeJSON sends a json response with encoding charset.
func (c *Controller) ServeJSON(encoding ...bool) {
var (
hasIndent = true
hasEncoding = false
hasIndent = BConfig.RunMode != PROD
hasEncoding = len(encoding) > 0 && encoding[0]
)
if BConfig.RunMode == PROD {
hasIndent = false
}
if len(encoding) > 0 && encoding[0] == true {
hasEncoding = true
}
c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding)
}
// ServeJSONP sends a jsonp response.
func (c *Controller) ServeJSONP() {
hasIndent := true
if BConfig.RunMode == PROD {
hasIndent = false
}
hasIndent := BConfig.RunMode != PROD
c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent)
}
// ServeXML sends xml response.
func (c *Controller) ServeXML() {
hasIndent := true
if BConfig.RunMode == PROD {
hasIndent = false
}
hasIndent := BConfig.RunMode != PROD
c.Ctx.Output.XML(c.Data["xml"], hasIndent)
}
// ServeFormatted serve Xml OR Json, depending on the value of the Accept header
func (c *Controller) ServeFormatted() {
accept := c.Ctx.Input.Header("Accept")
switch accept {
case applicationJSON:
c.ServeJSON()
case applicationXML, textXML:
c.ServeXML()
default:
c.ServeJSON()
}
// ServeYAML sends yaml response.
func (c *Controller) ServeYAML() {
c.Ctx.Output.YAML(c.Data["yaml"])
}
// ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header
func (c *Controller) ServeFormatted(encoding ...bool) {
hasIndent := BConfig.RunMode != PROD
hasEncoding := len(encoding) > 0 && encoding[0]
c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding)
}
// Input returns the input data map from POST or PUT request body and query string.

View File

@ -172,10 +172,10 @@ func TestAdditionalViewPaths(t *testing.T) {
t.Fatal("TestAdditionalViewPaths expected error")
}
}()
ctrl.RenderString();
ctrl.RenderString()
}()
ctrl.TplName = "file2.tpl"
ctrl.ViewPath = dir2
ctrl.RenderString();
ctrl.RenderString()
}

View File

@ -28,7 +28,7 @@ import (
)
const (
errorTypeHandler = iota
errorTypeHandler = iota
errorTypeController
)
@ -93,11 +93,6 @@ func showErr(err interface{}, ctx *context.Context, stack string) {
"BeegoVersion": VERSION,
"GoVersion": runtime.Version(),
}
if ctx.Output.Status != 0 {
ctx.ResponseWriter.WriteHeader(ctx.Output.Status)
} else {
ctx.ResponseWriter.WriteHeader(500)
}
t.Execute(ctx.ResponseWriter, data)
}
@ -252,6 +247,30 @@ func forbidden(rw http.ResponseWriter, r *http.Request) {
)
}
// show 422 missing xsrf token
func missingxsrf(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
422,
"<br>The page you have requested is forbidden."+
"<br>Perhaps you are here because:"+
"<br><br><ul>"+
"<br>'_xsrf' argument missing from POST"+
"</ul>",
)
}
// show 417 invalid xsrf token
func invalidxsrf(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
417,
"<br>The page you have requested is forbidden."+
"<br>Perhaps you are here because:"+
"<br><br><ul>"+
"<br>expected XSRF not found"+
"</ul>",
)
}
// show 404 not found error.
func notFound(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
@ -342,7 +361,7 @@ func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := map[string]interface{}{
data := M{
"Title": http.StatusText(errCode),
"BeegoVersion": VERSION,
"Content": template.HTML(errContent),
@ -415,6 +434,9 @@ func exception(errCode string, ctx *context.Context) {
}
func executeError(err *errorInfo, ctx *context.Context, code int) {
//make sure to log the error in the access log
LogAccess(ctx, nil, code)
if err.errorType == errorTypeHandler {
ctx.ResponseWriter.WriteHeader(code)
err.handler(ctx.ResponseWriter, ctx.Request)

View File

@ -52,7 +52,7 @@ func TestErrorCode_01(t *testing.T) {
if w.Code != code {
t.Fail()
}
if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) {
if !strings.Contains(w.Body.String(), http.StatusText(code)) {
t.Fail()
}
}
@ -82,7 +82,7 @@ func TestErrorCode_03(t *testing.T) {
if w.Code != 200 {
t.Fail()
}
if string(w.Body.Bytes()) != parseCodeError {
if w.Body.String() != parseCodeError {
t.Fail()
}
}

View File

@ -48,7 +48,7 @@ func TestFlashHeader(t *testing.T) {
// match for the expected header
res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00")
// validate the assertion
if res != true {
if !res {
t.Errorf("TestFlashHeader() unable to validate flash message")
}
}

74
fs.go Normal file
View File

@ -0,0 +1,74 @@
package beego
import (
"net/http"
"os"
"path/filepath"
)
type FileSystem struct {
}
func (d FileSystem) Open(name string) (http.File, error) {
return os.Open(name)
}
// Walk walks the file tree rooted at root in filesystem, calling walkFn for each file or
// directory in the tree, including root. All errors that arise visiting files
// and directories are filtered by walkFn.
func Walk(fs http.FileSystem, root string, walkFn filepath.WalkFunc) error {
f, err := fs.Open(root)
if err != nil {
return err
}
info, err := f.Stat()
if err != nil {
err = walkFn(root, nil, err)
} else {
err = walk(fs, root, info, walkFn)
}
if err == filepath.SkipDir {
return nil
}
return err
}
// walk recursively descends path, calling walkFn.
func walk(fs http.FileSystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
var err error
if !info.IsDir() {
return walkFn(path, info, nil)
}
dir, err := fs.Open(path)
if err != nil {
if err1 := walkFn(path, info, err); err1 != nil {
return err1
}
return err
}
defer dir.Close()
dirs, err := dir.Readdir(-1)
err1 := walkFn(path, info, err)
// If err != nil, walk can't walk into this directory.
// err1 != nil means walkFn want walk to skip this directory or stop walking.
// Therefore, if one of err and err1 isn't nil, walk will return.
if err != nil || err1 != nil {
// The caller's behavior is controlled by the return value, which is decided
// by walkFn. walkFn may ignore err and return nil.
// If walkFn returns SkipDir, it will be handled by the caller.
// So walk should return whatever walkFn returns.
return err1
}
for _, fileInfo := range dirs {
filename := filepath.Join(path, fileInfo.Name())
if err = walk(fs, filename, fileInfo, walkFn); err != nil {
if !fileInfo.IsDir() || err != filepath.SkipDir {
return err
}
}
}
return nil
}

40
go.mod Normal file
View File

@ -0,0 +1,40 @@
module github.com/astaxie/beego
require (
github.com/Knetic/govaluate v3.0.0+incompatible // indirect
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737
github.com/casbin/casbin v1.7.0
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808 // indirect
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a // indirect
github.com/elastic/go-elasticsearch/v6 v6.8.5
github.com/elazarl/go-bindata-assetfs v1.0.0
github.com/go-redis/redis v6.14.2+incompatible
github.com/go-sql-driver/mysql v1.5.0
github.com/gogo/protobuf v1.1.1
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/gomodule/redigo v2.0.0+incompatible
github.com/hashicorp/golang-lru v0.5.4
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6
github.com/lib/pq v1.0.0
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/pelletier/go-toml v1.2.0 // indirect
github.com/prometheus/client_golang v1.7.0
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec
github.com/stretchr/testify v1.4.0
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c // indirect
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b // indirect
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/tools v0.0.0-20200117065230-39095c1d176c
gopkg.in/yaml.v2 v2.2.8
)
replace golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 => github.com/golang/crypto v0.0.0-20181127143415-eb0de9b17e85
replace gopkg.in/yaml.v2 v2.2.1 => github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d
go 1.13

217
go.sum Normal file
View File

@ -0,0 +1,217 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd h1:jZtX5jh5IOMu0fpOTC3ayh6QGSPJ/KWOv1lgPvbRw1M=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542 h1:nYXb+3jF6Oq/j8R/y90XrKpreCxIalBWfeyeKymgOPk=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0 h1:PuzlE8w0JBg/DhIqnkF1Dewf3z+qmUZMVN07PonvVUQ=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d h1:OMrhQqj1QCyDT2sxHCDjE+k8aMdn2ngTCGG7g4wrdLo=
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808 h1:8s2l8TVUwMXl6tZMe3+hPCRJ25nQXiA3d1x622JtOqc=
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a h1:Y5XsLCEhtEI8qbD9RP3Qlv5FXdTDHxZM9UPUnMRgBp8=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/go-elasticsearch/v6 v6.8.5 h1:U2HtkBseC1FNBmDr0TR2tKltL6FxoY+niDAlj5M8TK8=
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-redis/redis v6.14.2+incompatible h1:UE9pLhzmWf+xHNmZsoccjXosPicuiNaInPgym8nzfg0=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d h1:xy93KVe+KrIIwWDEAfQBdIfsiHJkepbYsDr+VY3g9/o=
github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6 h1:wxyqOzKxsRJ6vVRL9sXQ64Z45wmBuQ+OTH9sLsC5rKc=
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/pingcap/tidb v2.0.11+incompatible/go.mod h1:I8C6jrPINP2rrVunTRd7C9fRRhQrtR43S1/CL5ix/yQ=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0 h1:QIF48X1cihydXibm+4wfAc0r/qyPyuFiPFRNphdMpEE=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec h1:q6XVwXmKvCRHRqesF3cSv6lNqqHi0QWOvgDlSohg8UA=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c h1:3eGShk3EQf5gJCYW+WzA0TEJQd37HLOmlYF7N0YJwv0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b h1:0Ve0/CCjiAiyKddUMUn3RwIGlq2iTW4GuVzyoKBYO/8=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20200117065230-39095c1d176c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -1,28 +0,0 @@
package grace
import (
"errors"
"net"
)
type graceConn struct {
net.Conn
server *Server
}
func (c graceConn) Close() (err error) {
defer func() {
if r := recover(); r != nil {
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("Unknown panic")
}
}
}()
c.server.wg.Done()
return c.Conn.Close()
}

View File

@ -78,7 +78,7 @@ var (
DefaultReadTimeOut time.Duration
// DefaultWriteTimeOut is the HTTP Write timeout
DefaultWriteTimeOut time.Duration
// DefaultMaxHeaderBytes is the Max HTTP Herder size, default is 0, no limit
// DefaultMaxHeaderBytes is the Max HTTP Header size, default is 0, no limit
DefaultMaxHeaderBytes int
// DefaultTimeout is the shutdown server's timeout. default is 60s
DefaultTimeout = 60 * time.Second
@ -122,7 +122,6 @@ func NewServer(addr string, handler http.Handler) (srv *Server) {
}
srv = &Server{
wg: sync.WaitGroup{},
sigChan: make(chan os.Signal),
isChild: isChild,
SignalHooks: map[int]map[os.Signal][]func(){
@ -137,20 +136,21 @@ func NewServer(addr string, handler http.Handler) (srv *Server) {
syscall.SIGTERM: {},
},
},
state: StateInit,
Network: "tcp",
state: StateInit,
Network: "tcp",
terminalChan: make(chan error), //no cache channel
}
srv.Server = &http.Server{
Addr: addr,
ReadTimeout: DefaultReadTimeOut,
WriteTimeout: DefaultWriteTimeOut,
MaxHeaderBytes: DefaultMaxHeaderBytes,
Handler: handler,
}
srv.Server = &http.Server{}
srv.Server.Addr = addr
srv.Server.ReadTimeout = DefaultReadTimeOut
srv.Server.WriteTimeout = DefaultWriteTimeOut
srv.Server.MaxHeaderBytes = DefaultMaxHeaderBytes
srv.Server.Handler = handler
runningServersOrder = append(runningServersOrder, addr)
runningServers[addr] = srv
return
return srv
}
// ListenAndServe refer http.ListenAndServe

View File

@ -1,62 +0,0 @@
package grace
import (
"net"
"os"
"syscall"
"time"
)
type graceListener struct {
net.Listener
stop chan error
stopped bool
server *Server
}
func newGraceListener(l net.Listener, srv *Server) (el *graceListener) {
el = &graceListener{
Listener: l,
stop: make(chan error),
server: srv,
}
go func() {
_ = <-el.stop
el.stopped = true
el.stop <- el.Listener.Close()
}()
return
}
func (gl *graceListener) Accept() (c net.Conn, err error) {
tc, err := gl.Listener.(*net.TCPListener).AcceptTCP()
if err != nil {
return
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
c = graceConn{
Conn: tc,
server: gl.server,
}
gl.server.wg.Add(1)
return
}
func (gl *graceListener) Close() error {
if gl.stopped {
return syscall.EINVAL
}
gl.stop <- nil
return <-gl.stop
}
func (gl *graceListener) File() *os.File {
// returns a dup(2) - FD_CLOEXEC flag *not* set
tl := gl.Listener.(*net.TCPListener)
fl, _ := tl.File()
return fl
}

View File

@ -1,8 +1,11 @@
package grace
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
@ -10,7 +13,6 @@ import (
"os/exec"
"os/signal"
"strings"
"sync"
"syscall"
"time"
)
@ -18,14 +20,13 @@ import (
// Server embedded http.Server
type Server struct {
*http.Server
GraceListener net.Listener
SignalHooks map[int]map[os.Signal][]func()
tlsInnerListener *graceListener
wg sync.WaitGroup
sigChan chan os.Signal
isChild bool
state uint8
Network string
ln net.Listener
SignalHooks map[int]map[os.Signal][]func()
sigChan chan os.Signal
isChild bool
state uint8
Network string
terminalChan chan error
}
// Serve accepts incoming connections on the Listener l,
@ -33,10 +34,21 @@ type Server struct {
// The service goroutines read requests and then call srv.Handler to reply to them.
func (srv *Server) Serve() (err error) {
srv.state = StateRunning
err = srv.Server.Serve(srv.GraceListener)
log.Println(syscall.Getpid(), "Waiting for connections to finish...")
srv.wg.Wait()
srv.state = StateTerminate
defer func() { srv.state = StateTerminate }()
// When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS
// immediately return ErrServerClosed. Make sure the program doesn't exit
// and waits instead for Shutdown to return.
if err = srv.Server.Serve(srv.ln); err != nil && err != http.ErrServerClosed {
log.Println(syscall.Getpid(), "Server.Serve() error:", err)
return err
}
log.Println(syscall.Getpid(), srv.ln.Addr(), "Listener closed.")
// wait for Shutdown to return
if shutdownErr := <-srv.terminalChan; shutdownErr != nil {
return shutdownErr
}
return
}
@ -51,21 +63,19 @@ func (srv *Server) ListenAndServe() (err error) {
go srv.handleSignals()
l, err := srv.getListener(addr)
srv.ln, err = srv.getListener(addr)
if err != nil {
log.Println(err)
return err
}
srv.GraceListener = newGraceListener(l, srv)
if srv.isChild {
process, err := os.FindProcess(os.Getppid())
if err != nil {
log.Println(err)
return err
}
err = process.Kill()
err = process.Signal(syscall.SIGTERM)
if err != nil {
return err
}
@ -105,14 +115,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
go srv.handleSignals()
l, err := srv.getListener(addr)
ln, err := srv.getListener(addr)
if err != nil {
log.Println(err)
return err
}
srv.tlsInnerListener = newGraceListener(l, srv)
srv.GraceListener = tls.NewListener(srv.tlsInnerListener, srv.TLSConfig)
srv.ln = tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig)
if srv.isChild {
process, err := os.FindProcess(os.Getppid())
@ -120,11 +128,67 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
log.Println(err)
return err
}
err = process.Kill()
err = process.Signal(syscall.SIGTERM)
if err != nil {
return err
}
}
log.Println(os.Getpid(), srv.Addr)
return srv.Serve()
}
// ListenAndServeMutualTLS listens on the TCP network address srv.Addr and then calls
// Serve to handle requests on incoming mutual TLS connections.
func (srv *Server) ListenAndServeMutualTLS(certFile, keyFile, trustFile string) (err error) {
addr := srv.Addr
if addr == "" {
addr = ":https"
}
if srv.TLSConfig == nil {
srv.TLSConfig = &tls.Config{}
}
if srv.TLSConfig.NextProtos == nil {
srv.TLSConfig.NextProtos = []string{"http/1.1"}
}
srv.TLSConfig.Certificates = make([]tls.Certificate, 1)
srv.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return
}
srv.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
pool := x509.NewCertPool()
data, err := ioutil.ReadFile(trustFile)
if err != nil {
log.Println(err)
return err
}
pool.AppendCertsFromPEM(data)
srv.TLSConfig.ClientCAs = pool
log.Println("Mutual HTTPS")
go srv.handleSignals()
ln, err := srv.getListener(addr)
if err != nil {
log.Println(err)
return err
}
srv.ln = tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig)
if srv.isChild {
process, err := os.FindProcess(os.Getppid())
if err != nil {
log.Println(err)
return err
}
err = process.Signal(syscall.SIGTERM)
if err != nil {
return err
}
}
log.Println(os.Getpid(), srv.Addr)
return srv.Serve()
}
@ -155,6 +219,20 @@ func (srv *Server) getListener(laddr string) (l net.Listener, err error) {
return
}
type tcpKeepAliveListener struct {
*net.TCPListener
}
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
tc, err := ln.AcceptTCP()
if err != nil {
return
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}
// handleSignals listens for os Signals and calls any hooked in function that the
// user had registered with the signal.
func (srv *Server) handleSignals() {
@ -196,7 +274,6 @@ func (srv *Server) signalHooks(ppFlag int, sig os.Signal) {
for _, f := range srv.SignalHooks[ppFlag][sig] {
f()
}
return
}
// shutdown closes the listener so that no new connections are accepted. it also
@ -208,37 +285,14 @@ func (srv *Server) shutdown() {
}
srv.state = StateShuttingDown
log.Println(syscall.Getpid(), "Waiting for connections to finish...")
ctx := context.Background()
if DefaultTimeout >= 0 {
go srv.serverTimeout(DefaultTimeout)
}
err := srv.GraceListener.Close()
if err != nil {
log.Println(syscall.Getpid(), "Listener.Close() error:", err)
} else {
log.Println(syscall.Getpid(), srv.GraceListener.Addr(), "Listener closed.")
}
}
// serverTimeout forces the server to shutdown in a given timeout - whether it
// finished outstanding requests or not. if Read/WriteTimeout are not set or the
// max header size is very big a connection could hang
func (srv *Server) serverTimeout(d time.Duration) {
defer func() {
if r := recover(); r != nil {
log.Println("WaitGroup at 0", r)
}
}()
if srv.state != StateShuttingDown {
return
}
time.Sleep(d)
log.Println("[STOP - Hammer Time] Forcefully shutting down parent")
for {
if srv.state == StateTerminate {
break
}
srv.wg.Done()
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
}
srv.terminalChan <- srv.Server.Shutdown(ctx)
}
func (srv *Server) fork() (err error) {
@ -252,12 +306,8 @@ func (srv *Server) fork() (err error) {
var files = make([]*os.File, len(runningServers))
var orderArgs = make([]string, len(runningServers))
for _, srvPtr := range runningServers {
switch srvPtr.GraceListener.(type) {
case *graceListener:
files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.GraceListener.(*graceListener).File()
default:
files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.tlsInnerListener.File()
}
f, _ := srvPtr.ln.(*net.TCPListener).File()
files[socketPtrOffsetMap[srvPtr.Server.Addr]] = f
orderArgs[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.Server.Addr
}
@ -292,7 +342,7 @@ func (srv *Server) fork() (err error) {
// RegisterSignalHook registers a function to be run PreSignal or PostSignal for a given signal.
func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err error) {
if ppFlag != PreSignal && ppFlag != PostSignal {
err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal.")
err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal")
return
}
for _, s := range hookableSignals {
@ -301,6 +351,6 @@ func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err
return
}
}
err = fmt.Errorf("Signal '%v' is not supported.", sig)
err = fmt.Errorf("Signal '%v' is not supported", sig)
return
}

View File

@ -11,7 +11,7 @@ import (
"github.com/astaxie/beego/session"
)
//
// register MIME type with content type
func registerMime() error {
for k, v := range mimemaps {
mime.AddExtensionType(k, v)
@ -32,6 +32,8 @@ func registerDefaultErrorHandler() error {
"502": badGateway,
"503": serviceUnavailable,
"504": gatewayTimeout,
"417": invalidxsrf,
"422": missingxsrf,
}
for e, h := range m {
if _, ok := ErrorMaps[e]; !ok {
@ -55,9 +57,9 @@ func registerSession() error {
conf.ProviderConfig = filepath.ToSlash(BConfig.WebConfig.Session.SessionProviderConfig)
conf.DisableHTTPOnly = BConfig.WebConfig.Session.SessionDisableHTTPOnly
conf.Domain = BConfig.WebConfig.Session.SessionDomain
conf.EnableSidInHttpHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader
conf.SessionNameInHttpHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader
conf.EnableSidInUrlQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery
conf.EnableSidInHTTPHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader
conf.SessionNameInHTTPHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader
conf.EnableSidInURLQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery
} else {
if err = json.Unmarshal([]byte(sessionConfig), conf); err != nil {
return err

View File

@ -32,7 +32,7 @@ The default timeout is `60` seconds, function prototype:
SetTimeout(connectTimeout, readWriteTimeout time.Duration)
Exmaple:
Example:
// GET
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)

View File

@ -47,9 +47,12 @@ import (
"net/http/httputil"
"net/url"
"os"
"path"
"strings"
"sync"
"time"
"gopkg.in/yaml.v2"
)
var defaultSetting = BeegoHTTPSettings{
@ -318,6 +321,34 @@ func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest {
return b
}
// XMLBody adds request raw body encoding by XML.
func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) {
if b.req.Body == nil && obj != nil {
byts, err := xml.Marshal(obj)
if err != nil {
return b, err
}
b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
b.req.ContentLength = int64(len(byts))
b.req.Header.Set("Content-Type", "application/xml")
}
return b, nil
}
// YAMLBody adds request raw body encoding by YAML.
func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) {
if b.req.Body == nil && obj != nil {
byts, err := yaml.Marshal(obj)
if err != nil {
return b, err
}
b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
b.req.ContentLength = int64(len(byts))
b.req.Header.Set("Content-Type", "application/x+yaml")
}
return b, nil
}
// JSONBody adds request raw body encoding by JSON.
func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) {
if b.req.Body == nil && obj != nil {
@ -335,7 +366,7 @@ func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error)
func (b *BeegoHTTPRequest) buildURL(paramBody string) {
// build GET url with query string
if b.req.Method == "GET" && len(paramBody) > 0 {
if strings.Index(b.url, "?") != -1 {
if strings.Contains(b.url, "?") {
b.url += "&" + paramBody
} else {
b.url = b.url + "?" + paramBody
@ -344,7 +375,7 @@ func (b *BeegoHTTPRequest) buildURL(paramBody string) {
}
// build POST/PUT/PATCH url and body
if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH") && b.req.Body == nil {
if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH" || b.req.Method == "DELETE") && b.req.Body == nil {
// with files
if len(b.files) > 0 {
pr, pw := io.Pipe()
@ -376,6 +407,7 @@ func (b *BeegoHTTPRequest) buildURL(paramBody string) {
}()
b.Header("Content-Type", bodyWriter.FormDataContentType())
b.req.Body = ioutil.NopCloser(pr)
b.Header("Transfer-Encoding", "chunked")
return
}
@ -417,12 +449,12 @@ func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) {
}
b.buildURL(paramBody)
url, err := url.Parse(b.url)
urlParsed, err := url.Parse(b.url)
if err != nil {
return nil, err
}
b.req.URL = url
b.req.URL = urlParsed
trans := b.setting.Transport
@ -432,7 +464,7 @@ func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) {
TLSClientConfig: b.setting.TLSClientConfig,
Proxy: b.setting.Proxy,
Dial: TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout),
MaxIdleConnsPerHost: -1,
MaxIdleConnsPerHost: 100,
}
} else {
// if b.transport is *http.Transport then set the settings.
@ -520,21 +552,15 @@ func (b *BeegoHTTPRequest) Bytes() ([]byte, error) {
return nil, err
}
b.body, err = ioutil.ReadAll(reader)
} else {
b.body, err = ioutil.ReadAll(resp.Body)
return b.body, err
}
b.body, err = ioutil.ReadAll(resp.Body)
return b.body, err
}
// ToFile saves the body data in response to one file.
// it calls Response inner.
func (b *BeegoHTTPRequest) ToFile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
resp, err := b.getResponse()
if err != nil {
return err
@ -543,10 +569,35 @@ func (b *BeegoHTTPRequest) ToFile(filename string) error {
return nil
}
defer resp.Body.Close()
err = pathExistAndMkdir(filename)
if err != nil {
return err
}
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
//Check that the file directory exists, there is no automatically created
func pathExistAndMkdir(filename string) (err error) {
filename = path.Dir(filename)
_, err = os.Stat(filename)
if err == nil {
return nil
}
if os.IsNotExist(err) {
err = os.MkdirAll(filename, os.ModePerm)
if err == nil {
return nil
}
}
return err
}
// ToJSON returns the map that marshals from the body bytes as json in response .
// it calls Response inner.
func (b *BeegoHTTPRequest) ToJSON(v interface{}) error {
@ -567,6 +618,16 @@ func (b *BeegoHTTPRequest) ToXML(v interface{}) error {
return xml.Unmarshal(data, v)
}
// ToYAML returns the map that marshals from the body bytes as yaml in response .
// it calls Response inner.
func (b *BeegoHTTPRequest) ToYAML(v interface{}) error {
data, err := b.Bytes()
if err != nil {
return err
}
return yaml.Unmarshal(data, v)
}
// Response executes request client gets response mannually.
func (b *BeegoHTTPRequest) Response() (*http.Response, error) {
return b.getResponse()

View File

@ -16,6 +16,8 @@ package httplib
import (
"io/ioutil"
"net"
"net/http"
"os"
"strings"
"testing"
@ -102,6 +104,14 @@ func TestSimpleDelete(t *testing.T) {
t.Log(str)
}
func TestSimpleDeleteParam(t *testing.T) {
str, err := Delete("http://httpbin.org/delete").Param("key", "val").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
}
func TestWithCookie(t *testing.T) {
v := "smallfish"
str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String()
@ -153,7 +163,16 @@ func TestWithSetting(t *testing.T) {
var setting BeegoHTTPSettings
setting.EnableCookie = true
setting.UserAgent = v
setting.Transport = nil
setting.Transport = &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 50,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
setting.ReadWriteTimeout = 5 * time.Second
SetDefaultSetting(setting)
@ -187,10 +206,16 @@ func TestToJson(t *testing.T) {
t.Fatal(err)
}
t.Log(ip.Origin)
if n := strings.Count(ip.Origin, "."); n != 3 {
ips := strings.Split(ip.Origin, ",")
if len(ips) == 0 {
t.Fatal("response is not valid ip")
}
for i := range ips {
if net.ParseIP(strings.TrimSpace(ips[i])).To4() == nil {
t.Fatal("response is not valid ip")
}
}
}
func TestToFile(t *testing.T) {
@ -207,6 +232,20 @@ func TestToFile(t *testing.T) {
}
}
func TestToFileDir(t *testing.T) {
f := "./files/beego_testfile"
req := Get("http://httpbin.org/ip")
err := req.ToFile(f)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll("./files")
b, err := ioutil.ReadFile(f)
if n := strings.Index(string(b), "origin"); n == -1 {
t.Fatal(err)
}
}
func TestHeader(t *testing.T) {
req := Get("http://httpbin.org/headers")
req.Header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36")

16
log.go
View File

@ -21,6 +21,7 @@ import (
)
// Log levels to control the logging output.
// Deprecated: use github.com/astaxie/beego/logs instead.
const (
LevelEmergency = iota
LevelAlert
@ -33,75 +34,90 @@ const (
)
// BeeLogger references the used application logger.
// Deprecated: use github.com/astaxie/beego/logs instead.
var BeeLogger = logs.GetBeeLogger()
// SetLevel sets the global log level used by the simple logger.
// Deprecated: use github.com/astaxie/beego/logs instead.
func SetLevel(l int) {
logs.SetLevel(l)
}
// SetLogFuncCall set the CallDepth, default is 3
// Deprecated: use github.com/astaxie/beego/logs instead.
func SetLogFuncCall(b bool) {
logs.SetLogFuncCall(b)
}
// SetLogger sets a new logger.
// Deprecated: use github.com/astaxie/beego/logs instead.
func SetLogger(adaptername string, config string) error {
return logs.SetLogger(adaptername, config)
}
// Emergency logs a message at emergency level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Emergency(v ...interface{}) {
logs.Emergency(generateFmtStr(len(v)), v...)
}
// Alert logs a message at alert level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Alert(v ...interface{}) {
logs.Alert(generateFmtStr(len(v)), v...)
}
// Critical logs a message at critical level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Critical(v ...interface{}) {
logs.Critical(generateFmtStr(len(v)), v...)
}
// Error logs a message at error level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Error(v ...interface{}) {
logs.Error(generateFmtStr(len(v)), v...)
}
// Warning logs a message at warning level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Warning(v ...interface{}) {
logs.Warning(generateFmtStr(len(v)), v...)
}
// Warn compatibility alias for Warning()
// Deprecated: use github.com/astaxie/beego/logs instead.
func Warn(v ...interface{}) {
logs.Warn(generateFmtStr(len(v)), v...)
}
// Notice logs a message at notice level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Notice(v ...interface{}) {
logs.Notice(generateFmtStr(len(v)), v...)
}
// Informational logs a message at info level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Informational(v ...interface{}) {
logs.Informational(generateFmtStr(len(v)), v...)
}
// Info compatibility alias for Warning()
// Deprecated: use github.com/astaxie/beego/logs instead.
func Info(v ...interface{}) {
logs.Info(generateFmtStr(len(v)), v...)
}
// Debug logs a message at debug level.
// Deprecated: use github.com/astaxie/beego/logs instead.
func Debug(v ...interface{}) {
logs.Debug(generateFmtStr(len(v)), v...)
}
// Trace logs a message at trace level.
// compatibility alias for Warning()
// Deprecated: use github.com/astaxie/beego/logs instead.
func Trace(v ...interface{}) {
logs.Trace(generateFmtStr(len(v)), v...)
}

View File

@ -16,48 +16,57 @@ As of now this logs support console, file,smtp and conn.
First you must import it
import (
"github.com/astaxie/beego/logs"
)
```golang
import (
"github.com/astaxie/beego/logs"
)
```
Then init a Log (example with console adapter)
log := NewLogger(10000)
log.SetLogger("console", "")
```golang
log := logs.NewLogger(10000)
log.SetLogger("console", "")
```
> the first params stand for how many channel
Use it like this:
log.Trace("trace")
log.Info("info")
log.Warn("warning")
log.Debug("debug")
log.Critical("critical")
Use it like this:
```golang
log.Trace("trace")
log.Info("info")
log.Warn("warning")
log.Debug("debug")
log.Critical("critical")
```
## File adapter
Configure file adapter like this:
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test.log"}`)
```golang
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test.log"}`)
```
## Conn adapter
Configure like this:
log := NewLogger(1000)
log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`)
log.Info("info")
```golang
log := NewLogger(1000)
log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`)
log.Info("info")
```
## Smtp adapter
Configure like this:
log := NewLogger(10000)
log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`)
log.Critical("sendmail critical")
time.Sleep(time.Second * 30)
```golang
log := NewLogger(10000)
log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`)
log.Critical("sendmail critical")
time.Sleep(time.Second * 30)
```

83
logs/accesslog.go Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package logs
import (
"bytes"
"strings"
"encoding/json"
"fmt"
"time"
)
const (
apacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f %s %s"
apacheFormat = "APACHE_FORMAT"
jsonFormat = "JSON_FORMAT"
)
// AccessLogRecord struct for holding access log data.
type AccessLogRecord struct {
RemoteAddr string `json:"remote_addr"`
RequestTime time.Time `json:"request_time"`
RequestMethod string `json:"request_method"`
Request string `json:"request"`
ServerProtocol string `json:"server_protocol"`
Host string `json:"host"`
Status int `json:"status"`
BodyBytesSent int64 `json:"body_bytes_sent"`
ElapsedTime time.Duration `json:"elapsed_time"`
HTTPReferrer string `json:"http_referrer"`
HTTPUserAgent string `json:"http_user_agent"`
RemoteUser string `json:"remote_user"`
}
func (r *AccessLogRecord) json() ([]byte, error) {
buffer := &bytes.Buffer{}
encoder := json.NewEncoder(buffer)
disableEscapeHTML(encoder)
err := encoder.Encode(r)
return buffer.Bytes(), err
}
func disableEscapeHTML(i interface{}) {
if e, ok := i.(interface {
SetEscapeHTML(bool)
}); ok {
e.SetEscapeHTML(false)
}
}
// AccessLog - Format and print access log.
func AccessLog(r *AccessLogRecord, format string) {
var msg string
switch format {
case apacheFormat:
timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05")
msg = fmt.Sprintf(apacheFormatPattern, r.RemoteAddr, timeFormatted, r.Request, r.Status, r.BodyBytesSent,
r.ElapsedTime.Seconds(), r.HTTPReferrer, r.HTTPUserAgent)
case jsonFormat:
fallthrough
default:
jsonData, err := r.json()
if err != nil {
msg = fmt.Sprintf(`{"Error": "%s"}`, err)
} else {
msg = string(jsonData)
}
}
beeLogger.writeMsg(levelLoggerImpl, strings.TrimSpace(msg))
}

View File

@ -2,19 +2,23 @@ package alils
import (
"encoding/json"
"github.com/astaxie/beego/logs"
"github.com/gogo/protobuf/proto"
"strings"
"sync"
"time"
"github.com/astaxie/beego/logs"
"github.com/gogo/protobuf/proto"
)
const (
CacheSize int = 64
// CacheSize set the flush size
CacheSize int = 64
// Delimiter define the topic delimiter
Delimiter string = "##"
)
type AliLSConfig struct {
// Config is the Config for Ali Log
type Config struct {
Project string `json:"project"`
Endpoint string `json:"endpoint"`
KeyID string `json:"key_id"`
@ -34,18 +38,17 @@ type aliLSWriter struct {
withMap bool
groupMap map[string]*LogGroup
lock *sync.Mutex
AliLSConfig
Config
}
// 创建提供Logger接口的日志服务
// NewAliLS create a new Logger
func NewAliLS() logs.Logger {
alils := new(aliLSWriter)
alils.Level = logs.LevelTrace
return alils
}
// 读取配置
// 初始化必要的数据结构
// Init parse config and init struct
func (c *aliLSWriter) Init(jsonConfig string) (err error) {
json.Unmarshal([]byte(jsonConfig), c)
@ -54,28 +57,26 @@ func (c *aliLSWriter) Init(jsonConfig string) (err error) {
c.FlushWhen = CacheSize
}
// 初始化Project
prj := &LogProject{
Name: c.Project,
Endpoint: c.Endpoint,
AccessKeyId: c.KeyID,
AccessKeyID: c.KeyID,
AccessKeySecret: c.KeySecret,
}
// 获取logstore
c.store, err = prj.GetLogStore(c.LogStore)
if err != nil {
return err
}
// 创建默认Log Group
// Create default Log Group
c.group = append(c.group, &LogGroup{
Topic: proto.String(""),
Source: proto.String(c.Source),
Logs: make([]*Log, 0, c.FlushWhen),
})
// 创建其它Log Group
// Create other Log Group
c.groupMap = make(map[string]*LogGroup)
for _, topic := range c.Topics {
@ -113,7 +114,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
var lg *LogGroup
if c.withMap {
// 解析出Topic并匹配LogGroup
// TopicLogGroup
strs := strings.SplitN(msg, Delimiter, 2)
if len(strs) == 2 {
pos := strings.LastIndex(strs[0], " ")
@ -122,27 +123,24 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
lg = c.groupMap[topic]
}
// 默认发到空Topic
// send to empty Topic
if lg == nil {
topic = ""
content = msg
lg = c.group[0]
}
} else {
topic = ""
content = msg
lg = c.group[0]
}
// 生成日志
c1 := &Log_Content{
c1 := &LogContent{
Key: proto.String("msg"),
Value: proto.String(content),
}
l := &Log{
Time: proto.Uint32(uint32(when.Unix())), // 填写日志时间
Contents: []*Log_Content{
Time: proto.Uint32(uint32(when.Unix())),
Contents: []*LogContent{
c1,
},
}
@ -151,7 +149,6 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
lg.Logs = append(lg.Logs, l)
c.lock.Unlock()
// 满足条件则Flush
if len(lg.Logs) >= c.FlushWhen {
c.flush(lg)
}
@ -162,7 +159,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
// Flush implementing method. empty.
func (c *aliLSWriter) Flush() {
// flush所有group
// flush all group
for _, lg := range c.group {
c.flush(lg)
}
@ -176,9 +173,6 @@ func (c *aliLSWriter) flush(lg *LogGroup) {
c.lock.Lock()
defer c.lock.Unlock()
// 把以上的LogGroup推送到SLS服务器
// SLS服务器会根据该logstore的shard个数自动进行负载均衡。
err := c.store.PutLogs(lg)
if err != nil {
return

View File

@ -1,30 +1,43 @@
package alils
import "github.com/gogo/protobuf/proto"
import "fmt"
import "math"
import (
"fmt"
"io"
"math"
// discarding unused import gogoproto "."
import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
import "io"
"github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var (
// ErrInvalidLengthLog invalid proto
ErrInvalidLengthLog = fmt.Errorf("proto: negative length found during unmarshaling")
// ErrIntOverflowLog overflow
ErrIntOverflowLog = fmt.Errorf("proto: integer overflow")
)
// Log define the proto Log
type Log struct {
Time *uint32 `protobuf:"varint,1,req,name=Time" json:"Time,omitempty"`
Contents []*Log_Content `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"`
XXX_unrecognized []byte `json:"-"`
Time *uint32 `protobuf:"varint,1,req,name=Time" json:"Time,omitempty"`
Contents []*LogContent `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *Log) Reset() { *m = Log{} }
func (m *Log) String() string { return proto.CompactTextString(m) }
func (*Log) ProtoMessage() {}
// Reset the Log
func (m *Log) Reset() { *m = Log{} }
// String return the Compact Log
func (m *Log) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*Log) ProtoMessage() {}
// GetTime return the Log's Time
func (m *Log) GetTime() uint32 {
if m != nil && m.Time != nil {
return *m.Time
@ -32,49 +45,65 @@ func (m *Log) GetTime() uint32 {
return 0
}
func (m *Log) GetContents() []*Log_Content {
// GetContents return the Log's Contents
func (m *Log) GetContents() []*LogContent {
if m != nil {
return m.Contents
}
return nil
}
type Log_Content struct {
Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"`
Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"`
XXX_unrecognized []byte `json:"-"`
// LogContent define the Log content struct
type LogContent struct {
Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"`
Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *Log_Content) Reset() { *m = Log_Content{} }
func (m *Log_Content) String() string { return proto.CompactTextString(m) }
func (*Log_Content) ProtoMessage() {}
// Reset LogContent
func (m *LogContent) Reset() { *m = LogContent{} }
func (m *Log_Content) GetKey() string {
// String return the compact text
func (m *LogContent) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*LogContent) ProtoMessage() {}
// GetKey return the Key
func (m *LogContent) GetKey() string {
if m != nil && m.Key != nil {
return *m.Key
}
return ""
}
func (m *Log_Content) GetValue() string {
// GetValue return the Value
func (m *LogContent) GetValue() string {
if m != nil && m.Value != nil {
return *m.Value
}
return ""
}
// LogGroup define the logs struct
type LogGroup struct {
Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"`
Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"`
Topic *string `protobuf:"bytes,3,opt,name=Topic" json:"Topic,omitempty"`
Source *string `protobuf:"bytes,4,opt,name=Source" json:"Source,omitempty"`
XXX_unrecognized []byte `json:"-"`
Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"`
Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"`
Topic *string `protobuf:"bytes,3,opt,name=Topic" json:"Topic,omitempty"`
Source *string `protobuf:"bytes,4,opt,name=Source" json:"Source,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *LogGroup) Reset() { *m = LogGroup{} }
func (m *LogGroup) String() string { return proto.CompactTextString(m) }
func (*LogGroup) ProtoMessage() {}
// Reset LogGroup
func (m *LogGroup) Reset() { *m = LogGroup{} }
// String return the compact text
func (m *LogGroup) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*LogGroup) ProtoMessage() {}
// GetLogs return the loggroup logs
func (m *LogGroup) GetLogs() []*Log {
if m != nil {
return m.Logs
@ -82,6 +111,7 @@ func (m *LogGroup) GetLogs() []*Log {
return nil
}
// GetReserved return Reserved
func (m *LogGroup) GetReserved() string {
if m != nil && m.Reserved != nil {
return *m.Reserved
@ -89,6 +119,7 @@ func (m *LogGroup) GetReserved() string {
return ""
}
// GetTopic return Topic
func (m *LogGroup) GetTopic() string {
if m != nil && m.Topic != nil {
return *m.Topic
@ -96,6 +127,7 @@ func (m *LogGroup) GetTopic() string {
return ""
}
// GetSource return Source
func (m *LogGroup) GetSource() string {
if m != nil && m.Source != nil {
return *m.Source
@ -103,15 +135,22 @@ func (m *LogGroup) GetSource() string {
return ""
}
// LogGroupList define the LogGroups
type LogGroupList struct {
LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"`
XXX_unrecognized []byte `json:"-"`
LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *LogGroupList) Reset() { *m = LogGroupList{} }
func (m *LogGroupList) String() string { return proto.CompactTextString(m) }
func (*LogGroupList) ProtoMessage() {}
// Reset LogGroupList
func (m *LogGroupList) Reset() { *m = LogGroupList{} }
// String return compact text
func (m *LogGroupList) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*LogGroupList) ProtoMessage() {}
// GetLogGroups return the LogGroups
func (m *LogGroupList) GetLogGroups() []*LogGroup {
if m != nil {
return m.LogGroups
@ -119,6 +158,7 @@ func (m *LogGroupList) GetLogGroups() []*LogGroup {
return nil
}
// Marshal the logs to byte slice
func (m *Log) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -129,6 +169,7 @@ func (m *Log) Marshal() (data []byte, err error) {
return data[:n], nil
}
// MarshalTo data
func (m *Log) MarshalTo(data []byte) (int, error) {
var i int
_ = i
@ -136,11 +177,10 @@ func (m *Log) MarshalTo(data []byte) (int, error) {
_ = l
if m.Time == nil {
return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Time")
} else {
data[i] = 0x8
i++
i = encodeVarintLog(data, i, uint64(*m.Time))
}
data[i] = 0x8
i++
i = encodeVarintLog(data, i, uint64(*m.Time))
if len(m.Contents) > 0 {
for _, msg := range m.Contents {
data[i] = 0x12
@ -153,13 +193,14 @@ func (m *Log) MarshalTo(data []byte) (int, error) {
i += n
}
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
func (m *Log_Content) Marshal() (data []byte, err error) {
// Marshal LogContent
func (m *LogContent) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
@ -169,33 +210,34 @@ func (m *Log_Content) Marshal() (data []byte, err error) {
return data[:n], nil
}
func (m *Log_Content) MarshalTo(data []byte) (int, error) {
// MarshalTo logcontent to data
func (m *LogContent) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Key == nil {
return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Key")
} else {
data[i] = 0xa
i++
i = encodeVarintLog(data, i, uint64(len(*m.Key)))
i += copy(data[i:], *m.Key)
}
data[i] = 0xa
i++
i = encodeVarintLog(data, i, uint64(len(*m.Key)))
i += copy(data[i:], *m.Key)
if m.Value == nil {
return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Value")
} else {
data[i] = 0x12
i++
i = encodeVarintLog(data, i, uint64(len(*m.Value)))
i += copy(data[i:], *m.Value)
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
data[i] = 0x12
i++
i = encodeVarintLog(data, i, uint64(len(*m.Value)))
i += copy(data[i:], *m.Value)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
// Marshal LogGroup
func (m *LogGroup) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -206,6 +248,7 @@ func (m *LogGroup) Marshal() (data []byte, err error) {
return data[:n], nil
}
// MarshalTo LogGroup to data
func (m *LogGroup) MarshalTo(data []byte) (int, error) {
var i int
_ = i
@ -241,12 +284,13 @@ func (m *LogGroup) MarshalTo(data []byte) (int, error) {
i = encodeVarintLog(data, i, uint64(len(*m.Source)))
i += copy(data[i:], *m.Source)
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
// Marshal LogGroupList
func (m *LogGroupList) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -257,6 +301,7 @@ func (m *LogGroupList) Marshal() (data []byte, err error) {
return data[:n], nil
}
// MarshalTo LogGroupList to data
func (m *LogGroupList) MarshalTo(data []byte) (int, error) {
var i int
_ = i
@ -274,8 +319,8 @@ func (m *LogGroupList) MarshalTo(data []byte) (int, error) {
i += n
}
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
@ -307,6 +352,8 @@ func encodeVarintLog(data []byte, offset int, v uint64) int {
data[offset] = uint8(v)
return offset + 1
}
// Size return the log's size
func (m *Log) Size() (n int) {
var l int
_ = l
@ -319,13 +366,14 @@ func (m *Log) Size() (n int) {
n += 1 + l + sovLog(uint64(l))
}
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
func (m *Log_Content) Size() (n int) {
// Size return LogContent size based on Key and Value
func (m *LogContent) Size() (n int) {
var l int
_ = l
if m.Key != nil {
@ -336,12 +384,13 @@ func (m *Log_Content) Size() (n int) {
l = len(*m.Value)
n += 1 + l + sovLog(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
// Size return LogGroup size based on Logs
func (m *LogGroup) Size() (n int) {
var l int
_ = l
@ -363,12 +412,13 @@ func (m *LogGroup) Size() (n int) {
l = len(*m.Source)
n += 1 + l + sovLog(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
// Size return LogGroupList size
func (m *LogGroupList) Size() (n int) {
var l int
_ = l
@ -378,8 +428,8 @@ func (m *LogGroupList) Size() (n int) {
n += 1 + l + sovLog(uint64(l))
}
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
@ -395,8 +445,10 @@ func sovLog(x uint64) (n int) {
return n
}
func sozLog(x uint64) (n int) {
return sovLog(uint64((x << 1) ^ uint64((int64(x) >> 63))))
return sovLog((x << 1) ^ (x >> 63))
}
// Unmarshal data to log
func (m *Log) Unmarshal(data []byte) error {
var hasFields [1]uint64
l := len(data)
@ -474,7 +526,7 @@ func (m *Log) Unmarshal(data []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Contents = append(m.Contents, &Log_Content{})
m.Contents = append(m.Contents, &LogContent{})
if err := m.Contents[len(m.Contents)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
return err
}
@ -491,7 +543,7 @@ func (m *Log) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -504,7 +556,9 @@ func (m *Log) Unmarshal(data []byte) error {
}
return nil
}
func (m *Log_Content) Unmarshal(data []byte) error {
// Unmarshal data to LogContent
func (m *LogContent) Unmarshal(data []byte) error {
var hasFields [1]uint64
l := len(data)
iNdEx := 0
@ -608,7 +662,7 @@ func (m *Log_Content) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -624,6 +678,8 @@ func (m *Log_Content) Unmarshal(data []byte) error {
}
return nil
}
// Unmarshal data to LogGroup
func (m *LogGroup) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
@ -786,7 +842,7 @@ func (m *LogGroup) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -796,6 +852,8 @@ func (m *LogGroup) Unmarshal(data []byte) error {
}
return nil
}
// Unmarshal data to LogGroupList
func (m *LogGroupList) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
@ -868,7 +926,7 @@ func (m *LogGroupList) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -878,6 +936,7 @@ func (m *LogGroupList) Unmarshal(data []byte) error {
}
return nil
}
func skipLog(data []byte) (n int, err error) {
l := len(data)
iNdEx := 0
@ -940,7 +999,7 @@ func skipLog(data []byte) (n int, err error) {
case 3:
for {
var innerWire uint64
var start int = iNdEx
var start = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowLog
@ -977,8 +1036,3 @@ func skipLog(data []byte) (n int, err error) {
}
panic("unreachable")
}
var (
ErrInvalidLengthLog = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowLog = fmt.Errorf("proto: integer overflow")
)

View File

@ -1,5 +1,6 @@
package alils
// InputDetail define log detail
type InputDetail struct {
LogType string `json:"logType"`
LogPath string `json:"logPath"`
@ -14,11 +15,13 @@ type InputDetail struct {
TopicFormat string `json:"topicFormat"`
}
// OutputDetail define the output detail
type OutputDetail struct {
Endpoint string `json:"endpoint"`
LogStoreName string `json:"logstoreName"`
}
// LogConfig define Log Config
type LogConfig struct {
Name string `json:"configName"`
InputType string `json:"inputType"`

View File

@ -1,5 +1,5 @@
/*
Package sls implements the SDK(v0.5.0) of Simple Log Service(abbr. SLS).
Package alils implements the SDK(v0.5.0) of Simple Log Service(abbr. SLS).
For more description about SLS, please read this article:
http://gitlab.alibaba-inc.com/sls/doc.
@ -20,19 +20,20 @@ type errorMessage struct {
Message string `json:"errorMessage"`
}
// LogProject Define the Ali Project detail
type LogProject struct {
Name string // Project name
Endpoint string // IP or hostname of SLS endpoint
AccessKeyId string
AccessKeyID string
AccessKeySecret string
}
// NewLogProject creates a new SLS project.
func NewLogProject(name, endpoint, accessKeyId, accessKeySecret string) (p *LogProject, err error) {
func NewLogProject(name, endpoint, AccessKeyID, accessKeySecret string) (p *LogProject, err error) {
p = &LogProject{
Name: name,
Endpoint: endpoint,
AccessKeyId: accessKeyId,
AccessKeyID: AccessKeyID,
AccessKeySecret: accessKeySecret,
}
return p, nil

View File

@ -12,6 +12,7 @@ import (
"github.com/gogo/protobuf/proto"
)
// LogStore Store the logs
type LogStore struct {
Name string `json:"logstoreName"`
TTL int
@ -23,6 +24,7 @@ type LogStore struct {
project *LogProject
}
// Shard define the Log Shard
type Shard struct {
ShardID int `json:"shardID"`
}
@ -116,16 +118,16 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) {
return
}
// GetCursor gets log cursor of one shard specified by shardId.
// GetCursor gets log cursor of one shard specified by shardID.
// The from can be in three form: a) unix timestamp in seccond, b) "begin", c) "end".
// For more detail please read: http://gitlab.alibaba-inc.com/sls/doc/blob/master/api/shard.md#logstore
func (s *LogStore) GetCursor(shardId int, from string) (cursor string, err error) {
func (s *LogStore) GetCursor(shardID int, from string) (cursor string, err error) {
h := map[string]string{
"x-sls-bodyrawsize": "0",
}
uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v",
s.Name, shardId, from)
s.Name, shardID, from)
r, err := request(s.project, "GET", uri, h, nil)
if err != nil {
@ -163,10 +165,10 @@ func (s *LogStore) GetCursor(shardId int, from string) (cursor string, err error
return
}
// GetLogsBytes gets logs binary data from shard specified by shardId according cursor.
// GetLogsBytes gets logs binary data from shard specified by shardID according cursor.
// The logGroupMaxCount is the max number of logGroup could be returned.
// The nextCursor is the next curosr can be used to read logs at next time.
func (s *LogStore) GetLogsBytes(shardId int, cursor string,
func (s *LogStore) GetLogsBytes(shardID int, cursor string,
logGroupMaxCount int) (out []byte, nextCursor string, err error) {
h := map[string]string{
@ -176,7 +178,7 @@ func (s *LogStore) GetLogsBytes(shardId int, cursor string,
}
uri := fmt.Sprintf("/logstores/%v/shards/%v?type=logs&cursor=%v&count=%v",
s.Name, shardId, cursor, logGroupMaxCount)
s.Name, shardID, cursor, logGroupMaxCount)
r, err := request(s.project, "GET", uri, h, nil)
if err != nil {
@ -249,13 +251,13 @@ func LogsBytesDecode(data []byte) (gl *LogGroupList, err error) {
return
}
// GetLogs gets logs from shard specified by shardId according cursor.
// GetLogs gets logs from shard specified by shardID according cursor.
// The logGroupMaxCount is the max number of logGroup could be returned.
// The nextCursor is the next curosr can be used to read logs at next time.
func (s *LogStore) GetLogs(shardId int, cursor string,
func (s *LogStore) GetLogs(shardID int, cursor string,
logGroupMaxCount int) (gl *LogGroupList, nextCursor string, err error) {
out, nextCursor, err := s.GetLogsBytes(shardId, cursor, logGroupMaxCount)
out, nextCursor, err := s.GetLogsBytes(shardID, cursor, logGroupMaxCount)
if err != nil {
return
}

View File

@ -8,18 +8,20 @@ import (
"net/http/httputil"
)
type MachinGroupAttribute struct {
// MachineGroupAttribute define the Attribute
type MachineGroupAttribute struct {
ExternalName string `json:"externalName"`
TopicName string `json:"groupTopic"`
}
// MachineGroup define the machine Group
type MachineGroup struct {
Name string `json:"groupName"`
Type string `json:"groupType"`
MachineIdType string `json:"machineIdentifyType"`
MachineIdList []string `json:"machineList"`
MachineIDType string `json:"machineIdentifyType"`
MachineIDList []string `json:"machineList"`
Attribute MachinGroupAttribute `json:"groupAttribute"`
Attribute MachineGroupAttribute `json:"groupAttribute"`
CreateTime uint32
LastModifyTime uint32
@ -27,12 +29,14 @@ type MachineGroup struct {
project *LogProject
}
// Machine define the Machine
type Machine struct {
IP string
UniqueId string `json:"machine-uniqueid"`
UserdefinedId string `json:"userdefined-id"`
UniqueID string `json:"machine-uniqueid"`
UserdefinedID string `json:"userdefined-id"`
}
// MachineList define the Machine List
type MachineList struct {
Total int
Machines []*Machine

View File

@ -33,12 +33,12 @@ func request(project *LogProject, method, uri string, headers map[string]string,
}
// Calc Authorization
// Authorization = "SLS <AccessKeyId>:<Signature>"
// Authorization = "SLS <AccessKeyID>:<Signature>"
digest, err := signature(project, method, uri, headers)
if err != nil {
return
}
auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyId, digest)
auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyID, digest)
headers["Authorization"] = auth
// Initialize http request

View File

@ -76,7 +76,7 @@ func signature(project *LogProject, method, uri string,
var keys sort.StringSlice
vals := u.Query()
for k, _ := range vals {
for k := range vals {
keys = append(keys, k)
}
@ -109,4 +109,3 @@ func signature(project *LogProject, method, uri string,
digest = base64.StdEncoding.EncodeToString(mac.Sum(nil))
return
}

View File

@ -1,428 +0,0 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build windows
package logs
import (
"bytes"
"io"
"strings"
"syscall"
"unsafe"
)
type (
csiState int
parseResult int
)
const (
outsideCsiCode csiState = iota
firstCsiCode
secondCsiCode
)
const (
noConsole parseResult = iota
changedColor
unknown
)
type ansiColorWriter struct {
w io.Writer
mode outputMode
state csiState
paramStartBuf bytes.Buffer
paramBuf bytes.Buffer
}
const (
firstCsiChar byte = '\x1b'
secondeCsiChar byte = '['
separatorChar byte = ';'
sgrCode byte = 'm'
)
const (
foregroundBlue = uint16(0x0001)
foregroundGreen = uint16(0x0002)
foregroundRed = uint16(0x0004)
foregroundIntensity = uint16(0x0008)
backgroundBlue = uint16(0x0010)
backgroundGreen = uint16(0x0020)
backgroundRed = uint16(0x0040)
backgroundIntensity = uint16(0x0080)
underscore = uint16(0x8000)
foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
)
const (
ansiReset = "0"
ansiIntensityOn = "1"
ansiIntensityOff = "21"
ansiUnderlineOn = "4"
ansiUnderlineOff = "24"
ansiBlinkOn = "5"
ansiBlinkOff = "25"
ansiForegroundBlack = "30"
ansiForegroundRed = "31"
ansiForegroundGreen = "32"
ansiForegroundYellow = "33"
ansiForegroundBlue = "34"
ansiForegroundMagenta = "35"
ansiForegroundCyan = "36"
ansiForegroundWhite = "37"
ansiForegroundDefault = "39"
ansiBackgroundBlack = "40"
ansiBackgroundRed = "41"
ansiBackgroundGreen = "42"
ansiBackgroundYellow = "43"
ansiBackgroundBlue = "44"
ansiBackgroundMagenta = "45"
ansiBackgroundCyan = "46"
ansiBackgroundWhite = "47"
ansiBackgroundDefault = "49"
ansiLightForegroundGray = "90"
ansiLightForegroundRed = "91"
ansiLightForegroundGreen = "92"
ansiLightForegroundYellow = "93"
ansiLightForegroundBlue = "94"
ansiLightForegroundMagenta = "95"
ansiLightForegroundCyan = "96"
ansiLightForegroundWhite = "97"
ansiLightBackgroundGray = "100"
ansiLightBackgroundRed = "101"
ansiLightBackgroundGreen = "102"
ansiLightBackgroundYellow = "103"
ansiLightBackgroundBlue = "104"
ansiLightBackgroundMagenta = "105"
ansiLightBackgroundCyan = "106"
ansiLightBackgroundWhite = "107"
)
type drawType int
const (
foreground drawType = iota
background
)
type winColor struct {
code uint16
drawType drawType
}
var colorMap = map[string]winColor{
ansiForegroundBlack: {0, foreground},
ansiForegroundRed: {foregroundRed, foreground},
ansiForegroundGreen: {foregroundGreen, foreground},
ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground},
ansiForegroundBlue: {foregroundBlue, foreground},
ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground},
ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
ansiBackgroundBlack: {0, background},
ansiBackgroundRed: {backgroundRed, background},
ansiBackgroundGreen: {backgroundGreen, background},
ansiBackgroundYellow: {backgroundRed | backgroundGreen, background},
ansiBackgroundBlue: {backgroundBlue, background},
ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background},
ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background},
ansiBackgroundDefault: {0, background},
ansiLightForegroundGray: {foregroundIntensity, foreground},
ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground},
ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground},
ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground},
ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},
ansiLightBackgroundGray: {backgroundIntensity, background},
ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background},
ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background},
ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background},
ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background},
ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background},
ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
}
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
defaultAttr *textAttributes
)
func init() {
screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
if screenInfo != nil {
colorMap[ansiForegroundDefault] = winColor{
screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
foreground,
}
colorMap[ansiBackgroundDefault] = winColor{
screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
background,
}
defaultAttr = convertTextAttr(screenInfo.WAttributes)
}
}
type coord struct {
X, Y int16
}
type smallRect struct {
Left, Top, Right, Bottom int16
}
type consoleScreenBufferInfo struct {
DwSize coord
DwCursorPosition coord
WAttributes uint16
SrWindow smallRect
DwMaximumWindowSize coord
}
func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
var csbi consoleScreenBufferInfo
ret, _, _ := procGetConsoleScreenBufferInfo.Call(
hConsoleOutput,
uintptr(unsafe.Pointer(&csbi)))
if ret == 0 {
return nil
}
return &csbi
}
func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
ret, _, _ := procSetConsoleTextAttribute.Call(
hConsoleOutput,
uintptr(wAttributes))
return ret != 0
}
type textAttributes struct {
foregroundColor uint16
backgroundColor uint16
foregroundIntensity uint16
backgroundIntensity uint16
underscore uint16
otherAttributes uint16
}
func convertTextAttr(winAttr uint16) *textAttributes {
fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
fgIntensity := winAttr & foregroundIntensity
bgIntensity := winAttr & backgroundIntensity
underline := winAttr & underscore
otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
}
func convertWinAttr(textAttr *textAttributes) uint16 {
var winAttr uint16
winAttr |= textAttr.foregroundColor
winAttr |= textAttr.backgroundColor
winAttr |= textAttr.foregroundIntensity
winAttr |= textAttr.backgroundIntensity
winAttr |= textAttr.underscore
winAttr |= textAttr.otherAttributes
return winAttr
}
func changeColor(param []byte) parseResult {
screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
if screenInfo == nil {
return noConsole
}
winAttr := convertTextAttr(screenInfo.WAttributes)
strParam := string(param)
if len(strParam) <= 0 {
strParam = "0"
}
csiParam := strings.Split(strParam, string(separatorChar))
for _, p := range csiParam {
c, ok := colorMap[p]
switch {
case !ok:
switch p {
case ansiReset:
winAttr.foregroundColor = defaultAttr.foregroundColor
winAttr.backgroundColor = defaultAttr.backgroundColor
winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
winAttr.underscore = 0
winAttr.otherAttributes = 0
case ansiIntensityOn:
winAttr.foregroundIntensity = foregroundIntensity
case ansiIntensityOff:
winAttr.foregroundIntensity = 0
case ansiUnderlineOn:
winAttr.underscore = underscore
case ansiUnderlineOff:
winAttr.underscore = 0
case ansiBlinkOn:
winAttr.backgroundIntensity = backgroundIntensity
case ansiBlinkOff:
winAttr.backgroundIntensity = 0
default:
// unknown code
}
case c.drawType == foreground:
winAttr.foregroundColor = c.code
case c.drawType == background:
winAttr.backgroundColor = c.code
}
}
winTextAttribute := convertWinAttr(winAttr)
setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
return changedColor
}
func parseEscapeSequence(command byte, param []byte) parseResult {
if defaultAttr == nil {
return noConsole
}
switch command {
case sgrCode:
return changeColor(param)
default:
return unknown
}
}
func (cw *ansiColorWriter) flushBuffer() (int, error) {
return cw.flushTo(cw.w)
}
func (cw *ansiColorWriter) resetBuffer() (int, error) {
return cw.flushTo(nil)
}
func (cw *ansiColorWriter) flushTo(w io.Writer) (int, error) {
var n1, n2 int
var err error
startBytes := cw.paramStartBuf.Bytes()
cw.paramStartBuf.Reset()
if w != nil {
n1, err = cw.w.Write(startBytes)
if err != nil {
return n1, err
}
} else {
n1 = len(startBytes)
}
paramBytes := cw.paramBuf.Bytes()
cw.paramBuf.Reset()
if w != nil {
n2, err = cw.w.Write(paramBytes)
if err != nil {
return n1 + n2, err
}
} else {
n2 = len(paramBytes)
}
return n1 + n2, nil
}
func isParameterChar(b byte) bool {
return ('0' <= b && b <= '9') || b == separatorChar
}
func (cw *ansiColorWriter) Write(p []byte) (int, error) {
r, nw, first, last := 0, 0, 0, 0
if cw.mode != DiscardNonColorEscSeq {
cw.state = outsideCsiCode
cw.resetBuffer()
}
var err error
for i, ch := range p {
switch cw.state {
case outsideCsiCode:
if ch == firstCsiChar {
cw.paramStartBuf.WriteByte(ch)
cw.state = firstCsiCode
}
case firstCsiCode:
switch ch {
case firstCsiChar:
cw.paramStartBuf.WriteByte(ch)
break
case secondeCsiChar:
cw.paramStartBuf.WriteByte(ch)
cw.state = secondCsiCode
last = i - 1
default:
cw.resetBuffer()
cw.state = outsideCsiCode
}
case secondCsiCode:
if isParameterChar(ch) {
cw.paramBuf.WriteByte(ch)
} else {
nw, err = cw.w.Write(p[first:last])
r += nw
if err != nil {
return r, err
}
first = i + 1
result := parseEscapeSequence(ch, cw.paramBuf.Bytes())
if result == noConsole || (cw.mode == OutputNonColorEscSeq && result == unknown) {
cw.paramBuf.WriteByte(ch)
nw, err := cw.flushBuffer()
if err != nil {
return r, err
}
r += nw
} else {
n, _ := cw.resetBuffer()
// Add one more to the size of the buffer for the last ch
r += n + 1
}
cw.state = outsideCsiCode
}
default:
cw.state = outsideCsiCode
}
}
if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode {
nw, err = cw.w.Write(p[first:])
r += nw
}
return r, err
}

View File

@ -1,294 +0,0 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build windows
package logs
import (
"bytes"
"fmt"
"syscall"
"testing"
)
var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo
func ChangeColor(color uint16) {
setConsoleTextAttribute(uintptr(syscall.Stdout), color)
}
func ResetColor() {
ChangeColor(uint16(0x0007))
}
func TestWritePlanText(t *testing.T) {
inner := bytes.NewBufferString("")
w := NewAnsiColorWriter(inner)
expected := "plain text"
fmt.Fprintf(w, expected)
actual := inner.String()
if actual != expected {
t.Errorf("Get %q, want %q", actual, expected)
}
}
func TestWriteParseText(t *testing.T) {
inner := bytes.NewBufferString("")
w := NewAnsiColorWriter(inner)
inputTail := "\x1b[0mtail text"
expectedTail := "tail text"
fmt.Fprintf(w, inputTail)
actualTail := inner.String()
inner.Reset()
if actualTail != expectedTail {
t.Errorf("Get %q, want %q", actualTail, expectedTail)
}
inputHead := "head text\x1b[0m"
expectedHead := "head text"
fmt.Fprintf(w, inputHead)
actualHead := inner.String()
inner.Reset()
if actualHead != expectedHead {
t.Errorf("Get %q, want %q", actualHead, expectedHead)
}
inputBothEnds := "both ends \x1b[0m text"
expectedBothEnds := "both ends text"
fmt.Fprintf(w, inputBothEnds)
actualBothEnds := inner.String()
inner.Reset()
if actualBothEnds != expectedBothEnds {
t.Errorf("Get %q, want %q", actualBothEnds, expectedBothEnds)
}
inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc"
expectedManyEsc := "\x1b\x1b\x1b many esc"
fmt.Fprintf(w, inputManyEsc)
actualManyEsc := inner.String()
inner.Reset()
if actualManyEsc != expectedManyEsc {
t.Errorf("Get %q, want %q", actualManyEsc, expectedManyEsc)
}
expectedSplit := "split text"
for _, ch := range "split \x1b[0m text" {
fmt.Fprintf(w, string(ch))
}
actualSplit := inner.String()
inner.Reset()
if actualSplit != expectedSplit {
t.Errorf("Get %q, want %q", actualSplit, expectedSplit)
}
}
type screenNotFoundError struct {
error
}
func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) {
inner := bytes.NewBufferString("")
w := NewAnsiColorWriter(inner)
fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText)
actualText = inner.String()
screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
if screenInfo != nil {
actualAttributes = screenInfo.WAttributes
} else {
err = &screenNotFoundError{}
}
return
}
type testParam struct {
text string
attributes uint16
ansiColor string
}
func TestWriteAnsiColorText(t *testing.T) {
screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
if screenInfo == nil {
t.Fatal("Could not get ConsoleScreenBufferInfo")
}
defer ChangeColor(screenInfo.WAttributes)
defaultFgColor := screenInfo.WAttributes & uint16(0x0007)
defaultBgColor := screenInfo.WAttributes & uint16(0x0070)
defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008)
defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080)
fgParam := []testParam{
{"foreground black ", uint16(0x0000 | 0x0000), "30"},
{"foreground red ", uint16(0x0004 | 0x0000), "31"},
{"foreground green ", uint16(0x0002 | 0x0000), "32"},
{"foreground yellow ", uint16(0x0006 | 0x0000), "33"},
{"foreground blue ", uint16(0x0001 | 0x0000), "34"},
{"foreground magenta", uint16(0x0005 | 0x0000), "35"},
{"foreground cyan ", uint16(0x0003 | 0x0000), "36"},
{"foreground white ", uint16(0x0007 | 0x0000), "37"},
{"foreground default", defaultFgColor | 0x0000, "39"},
{"foreground light gray ", uint16(0x0000 | 0x0008 | 0x0000), "90"},
{"foreground light red ", uint16(0x0004 | 0x0008 | 0x0000), "91"},
{"foreground light green ", uint16(0x0002 | 0x0008 | 0x0000), "92"},
{"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"},
{"foreground light blue ", uint16(0x0001 | 0x0008 | 0x0000), "94"},
{"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"},
{"foreground light cyan ", uint16(0x0003 | 0x0008 | 0x0000), "96"},
{"foreground light white ", uint16(0x0007 | 0x0008 | 0x0000), "97"},
}
bgParam := []testParam{
{"background black ", uint16(0x0007 | 0x0000), "40"},
{"background red ", uint16(0x0007 | 0x0040), "41"},
{"background green ", uint16(0x0007 | 0x0020), "42"},
{"background yellow ", uint16(0x0007 | 0x0060), "43"},
{"background blue ", uint16(0x0007 | 0x0010), "44"},
{"background magenta", uint16(0x0007 | 0x0050), "45"},
{"background cyan ", uint16(0x0007 | 0x0030), "46"},
{"background white ", uint16(0x0007 | 0x0070), "47"},
{"background default", uint16(0x0007) | defaultBgColor, "49"},
{"background light gray ", uint16(0x0007 | 0x0000 | 0x0080), "100"},
{"background light red ", uint16(0x0007 | 0x0040 | 0x0080), "101"},
{"background light green ", uint16(0x0007 | 0x0020 | 0x0080), "102"},
{"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"},
{"background light blue ", uint16(0x0007 | 0x0010 | 0x0080), "104"},
{"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"},
{"background light cyan ", uint16(0x0007 | 0x0030 | 0x0080), "106"},
{"background light white ", uint16(0x0007 | 0x0070 | 0x0080), "107"},
}
resetParam := []testParam{
{"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"},
{"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""},
}
boldParam := []testParam{
{"bold on", uint16(0x0007 | 0x0008), "1"},
{"bold off", uint16(0x0007), "21"},
}
underscoreParam := []testParam{
{"underscore on", uint16(0x0007 | 0x8000), "4"},
{"underscore off", uint16(0x0007), "24"},
}
blinkParam := []testParam{
{"blink on", uint16(0x0007 | 0x0080), "5"},
{"blink off", uint16(0x0007), "25"},
}
mixedParam := []testParam{
{"both black, bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"},
{"both red, bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"},
{"both green, bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"},
{"both yellow, bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"},
{"both blue, bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"},
{"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"},
{"both cyan, bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"},
{"both white, bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"},
{"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"},
}
assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) {
actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor)
if actualText != expectedText {
t.Errorf("Get %q, want %q", actualText, expectedText)
}
if err != nil {
t.Fatal("Could not get ConsoleScreenBufferInfo")
}
if actualAttributes != expectedAttributes {
t.Errorf("Text: %q, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes)
}
}
for _, v := range fgParam {
ResetColor()
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
for _, v := range bgParam {
ChangeColor(uint16(0x0070 | 0x0007))
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
for _, v := range resetParam {
ChangeColor(uint16(0x0000 | 0x0070 | 0x0008))
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
ResetColor()
for _, v := range boldParam {
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
ResetColor()
for _, v := range underscoreParam {
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
ResetColor()
for _, v := range blinkParam {
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
for _, v := range mixedParam {
ResetColor()
assertTextAttribute(v.text, v.attributes, v.ansiColor)
}
}
func TestIgnoreUnknownSequences(t *testing.T) {
inner := bytes.NewBufferString("")
w := NewModeAnsiColorWriter(inner, OutputNonColorEscSeq)
inputText := "\x1b[=decpath mode"
expectedTail := inputText
fmt.Fprintf(w, inputText)
actualTail := inner.String()
inner.Reset()
if actualTail != expectedTail {
t.Errorf("Get %q, want %q", actualTail, expectedTail)
}
inputText = "\x1b[=tailing esc and bracket\x1b["
expectedTail = inputText
fmt.Fprintf(w, inputText)
actualTail = inner.String()
inner.Reset()
if actualTail != expectedTail {
t.Errorf("Get %q, want %q", actualTail, expectedTail)
}
inputText = "\x1b[?tailing esc\x1b"
expectedTail = inputText
fmt.Fprintf(w, inputText)
actualTail = inner.String()
inner.Reset()
if actualTail != expectedTail {
t.Errorf("Get %q, want %q", actualTail, expectedTail)
}
inputText = "\x1b[1h;3punended color code invalid\x1b3"
expectedTail = inputText
fmt.Fprintf(w, inputText)
actualTail = inner.String()
inner.Reset()
if actualTail != expectedTail {
t.Errorf("Get %q, want %q", actualTail, expectedTail)
}
}

View File

@ -63,7 +63,7 @@ func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error {
defer c.innerWriter.Close()
}
c.lg.println(when, msg)
c.lg.writeln(when, msg)
return nil
}

View File

@ -17,8 +17,10 @@ package logs
import (
"encoding/json"
"os"
"runtime"
"strings"
"time"
"github.com/shiena/ansicolor"
)
// brush is a color join function
@ -41,7 +43,7 @@ var colors = []brush{
newBrush("1;33"), // Warning yellow
newBrush("1;32"), // Notice green
newBrush("1;34"), // Informational blue
newBrush("1;34"), // Debug blue
newBrush("1;44"), // Debug Background blue
}
// consoleWriter implements LoggerInterface and writes messages to terminal.
@ -54,9 +56,9 @@ type consoleWriter struct {
// NewConsole create ConsoleWriter returning as LoggerInterface.
func NewConsole() Logger {
cw := &consoleWriter{
lg: newLogWriter(os.Stdout),
lg: newLogWriter(ansicolor.NewAnsiColorWriter(os.Stdout)),
Level: LevelDebug,
Colorful: runtime.GOOS != "windows",
Colorful: true,
}
return cw
}
@ -67,11 +69,7 @@ func (c *consoleWriter) Init(jsonConfig string) error {
if len(jsonConfig) == 0 {
return nil
}
err := json.Unmarshal([]byte(jsonConfig), c)
if runtime.GOOS == "windows" {
c.Colorful = false
}
return err
return json.Unmarshal([]byte(jsonConfig), c)
}
// WriteMsg write message in console.
@ -80,9 +78,9 @@ func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error {
return nil
}
if c.Colorful {
msg = colors[level](msg)
msg = strings.Replace(msg, levelPrefix[level], colors[level](levelPrefix[level]), 1)
}
c.lg.println(when, msg)
c.lg.writeln(when, msg)
return nil
}

View File

@ -16,6 +16,7 @@ package logs
import (
"testing"
"time"
)
// Try each log level in decreasing order of priority.
@ -49,3 +50,15 @@ func TestConsoleNoColor(t *testing.T) {
log.SetLogger("console", `{"color":false}`)
testConsoleCalls(log)
}
// Test console async
func TestConsoleAsync(t *testing.T) {
log := NewLogger(100)
log.SetLogger("console")
log.Async()
//log.Close()
testConsoleCalls(log)
for len(log.msgChan) != 0 {
time.Sleep(1 * time.Millisecond)
}
}

View File

@ -1,15 +1,18 @@
package es
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"net/url"
"strings"
"time"
"github.com/elastic/go-elasticsearch/v6"
"github.com/elastic/go-elasticsearch/v6/esapi"
"github.com/astaxie/beego/logs"
"github.com/belogik/goes"
)
// NewES return a LoggerInterface
@ -20,8 +23,14 @@ func NewES() logs.Logger {
return cw
}
// esLogger will log msg into ES
// before you using this implementation,
// please import this package
// usually means that you can import this package in your main package
// for example, anonymous:
// import _ "github.com/astaxie/beego/logs/es"
type esLogger struct {
*goes.Connection
*elasticsearch.Client
DSN string `json:"dsn"`
Level int `json:"level"`
}
@ -38,11 +47,14 @@ func (el *esLogger) Init(jsonconfig string) error {
return err
} else if u.Path == "" {
return errors.New("missing prefix")
} else if host, port, err := net.SplitHostPort(u.Host); err != nil {
return err
} else {
conn := goes.NewConnection(host, port)
el.Connection = conn
conn, err := elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{el.DSN},
})
if err != nil {
return err
}
el.Client = conn
}
return nil
}
@ -53,21 +65,26 @@ func (el *esLogger) WriteMsg(when time.Time, msg string, level int) error {
return nil
}
vals := make(map[string]interface{})
vals["@timestamp"] = when.Format(time.RFC3339)
vals["@msg"] = msg
d := goes.Document{
Index: fmt.Sprintf("%04d.%02d.%02d", when.Year(), when.Month(), when.Day()),
Type: "logs",
Fields: vals,
idx := LogDocument{
Timestamp: when.Format(time.RFC3339),
Msg: msg,
}
_, err := el.Index(d, nil)
body, err := json.Marshal(idx)
if err != nil {
return err
}
req := esapi.IndexRequest{
Index: fmt.Sprintf("%04d.%02d.%02d", when.Year(), when.Month(), when.Day()),
DocumentType: "logs",
Body: strings.NewReader(string(body)),
}
_, err = req.Do(context.Background(), el.Client)
return err
}
// Destroy is a empty method
func (el *esLogger) Destroy() {
}
// Flush is a empty method
@ -75,6 +92,11 @@ func (el *esLogger) Flush() {
}
type LogDocument struct {
Timestamp string `json:"timestamp"`
Msg string `json:"msg"`
}
func init() {
logs.Register(logs.AdapterEs, NewES)
}

View File

@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strconv"
"strings"
@ -40,6 +41,9 @@ type fileLogWriter struct {
MaxLines int `json:"maxlines"`
maxLinesCurLines int
MaxFiles int `json:"maxfiles"`
MaxFilesCurFiles int
// Rotate at size
MaxSize int `json:"maxsize"`
maxSizeCurSize int
@ -50,38 +54,52 @@ type fileLogWriter struct {
dailyOpenDate int
dailyOpenTime time.Time
// Rotate hourly
Hourly bool `json:"hourly"`
MaxHours int64 `json:"maxhours"`
hourlyOpenDate int
hourlyOpenTime time.Time
Rotate bool `json:"rotate"`
Level int `json:"level"`
Perm string `json:"perm"`
RotatePerm string `json:"rotateperm"`
fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix
}
// newFileWriter create a FileLogWriter returning as LoggerInterface.
func newFileWriter() Logger {
w := &fileLogWriter{
Daily: true,
MaxDays: 7,
Rotate: true,
Level: LevelTrace,
Perm: "0660",
Daily: true,
MaxDays: 7,
Hourly: false,
MaxHours: 168,
Rotate: true,
RotatePerm: "0440",
Level: LevelTrace,
Perm: "0660",
MaxLines: 10000000,
MaxFiles: 999,
MaxSize: 1 << 28,
}
return w
}
// Init file logger with json config.
// jsonConfig like:
// {
// "filename":"logs/beego.log",
// "maxLines":10000,
// "maxsize":1024,
// "daily":true,
// "maxDays":15,
// "rotate":true,
// "perm":"0600"
// }
// {
// "filename":"logs/beego.log",
// "maxLines":10000,
// "maxsize":1024,
// "daily":true,
// "maxDays":15,
// "rotate":true,
// "perm":"0600"
// }
func (w *fileLogWriter) Init(jsonConfig string) error {
err := json.Unmarshal([]byte(jsonConfig), w)
if err != nil {
@ -112,10 +130,16 @@ func (w *fileLogWriter) startLogger() error {
return w.initFd()
}
func (w *fileLogWriter) needRotate(size int, day int) bool {
func (w *fileLogWriter) needRotateDaily(size int, day int) bool {
return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
(w.Daily && day != w.dailyOpenDate)
}
func (w *fileLogWriter) needRotateHourly(size int, hour int) bool {
return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
(w.Hourly && hour != w.hourlyOpenDate)
}
@ -124,14 +148,23 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
if level > w.Level {
return nil
}
h, d := formatTimeHeader(when)
msg = string(h) + msg + "\n"
hd, d, h := formatTimeHeader(when)
msg = string(hd) + msg + "\n"
if w.Rotate {
w.RLock()
if w.needRotate(len(msg), d) {
if w.needRotateHourly(len(msg), h) {
w.RUnlock()
w.Lock()
if w.needRotate(len(msg), d) {
if w.needRotateHourly(len(msg), h) {
if err := w.doRotate(when); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
}
w.Unlock()
} else if w.needRotateDaily(len(msg), d) {
w.RUnlock()
w.Lock()
if w.needRotateDaily(len(msg), d) {
if err := w.doRotate(when); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
@ -158,6 +191,10 @@ func (w *fileLogWriter) createLogFile() (*os.File, error) {
if err != nil {
return nil, err
}
filepath := path.Dir(w.Filename)
os.MkdirAll(filepath, os.FileMode(perm))
fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm))
if err == nil {
// Make sure file perm is user set perm cause of `os.OpenFile` will obey umask
@ -170,16 +207,20 @@ func (w *fileLogWriter) initFd() error {
fd := w.fileWriter
fInfo, err := fd.Stat()
if err != nil {
return fmt.Errorf("get stat err: %s\n", err)
return fmt.Errorf("get stat err: %s", err)
}
w.maxSizeCurSize = int(fInfo.Size())
w.dailyOpenTime = time.Now()
w.dailyOpenDate = w.dailyOpenTime.Day()
w.hourlyOpenTime = time.Now()
w.hourlyOpenDate = w.hourlyOpenTime.Hour()
w.maxLinesCurLines = 0
if w.Daily {
if w.Hourly {
go w.hourlyRotate(w.hourlyOpenTime)
} else if w.Daily {
go w.dailyRotate(w.dailyOpenTime)
}
if fInfo.Size() > 0 {
if fInfo.Size() > 0 && w.MaxLines > 0 {
count, err := w.lines()
if err != nil {
return err
@ -193,16 +234,29 @@ func (w *fileLogWriter) dailyRotate(openTime time.Time) {
y, m, d := openTime.Add(24 * time.Hour).Date()
nextDay := time.Date(y, m, d, 0, 0, 0, 0, openTime.Location())
tm := time.NewTimer(time.Duration(nextDay.UnixNano() - openTime.UnixNano() + 100))
select {
case <-tm.C:
w.Lock()
if w.needRotate(0, time.Now().Day()) {
if err := w.doRotate(time.Now()); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
<-tm.C
w.Lock()
if w.needRotateDaily(0, time.Now().Day()) {
if err := w.doRotate(time.Now()); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
w.Unlock()
}
w.Unlock()
}
func (w *fileLogWriter) hourlyRotate(openTime time.Time) {
y, m, d := openTime.Add(1 * time.Hour).Date()
h, _, _ := openTime.Add(1 * time.Hour).Clock()
nextHour := time.Date(y, m, d, h, 0, 0, 0, openTime.Location())
tm := time.NewTimer(time.Duration(nextHour.UnixNano() - openTime.UnixNano() + 100))
<-tm.C
w.Lock()
if w.needRotateHourly(0, time.Now().Hour()) {
if err := w.doRotate(time.Now()); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
}
w.Unlock()
}
func (w *fileLogWriter) lines() (int, error) {
@ -237,31 +291,44 @@ func (w *fileLogWriter) lines() (int, error) {
func (w *fileLogWriter) doRotate(logTime time.Time) error {
// file exists
// Find the next available number
num := 1
num := w.MaxFilesCurFiles + 1
fName := ""
format := ""
var openTime time.Time
rotatePerm, err := strconv.ParseInt(w.RotatePerm, 8, 64)
if err != nil {
return err
}
_, err := os.Lstat(w.Filename)
_, err = os.Lstat(w.Filename)
if err != nil {
//even if the file is not exist or other ,we should RESTART the logger
goto RESTART_LOGGER
}
if w.Hourly {
format = "2006010215"
openTime = w.hourlyOpenTime
} else if w.Daily {
format = "2006-01-02"
openTime = w.dailyOpenTime
}
// only when one of them be setted, then the file would be splited
if w.MaxLines > 0 || w.MaxSize > 0 {
for ; err == nil && num <= 999; num++ {
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix)
for ; err == nil && num <= w.MaxFiles; num++ {
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format(format), num, w.suffix)
_, err = os.Lstat(fName)
}
} else {
fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, w.dailyOpenTime.Format("2006-01-02"), w.suffix)
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", openTime.Format(format), num, w.suffix)
_, err = os.Lstat(fName)
for ; err == nil && num <= 999; num++ {
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", w.dailyOpenTime.Format("2006-01-02"), num, w.suffix)
_, err = os.Lstat(fName)
}
w.MaxFilesCurFiles = num
}
// return error if the last file checked still existed
if err == nil {
return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.Filename)
return fmt.Errorf("Rotate: Cannot find free log number to rename %s", w.Filename)
}
// close fileWriter before rename
@ -270,25 +337,32 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error {
// Rename the file to its new found name
// even if occurs error,we MUST guarantee to restart new logger
err = os.Rename(w.Filename, fName)
err = os.Chmod(fName, os.FileMode(440))
// re-start logger
if err != nil {
goto RESTART_LOGGER
}
err = os.Chmod(fName, os.FileMode(rotatePerm))
RESTART_LOGGER:
startLoggerErr := w.startLogger()
go w.deleteOldLog()
if startLoggerErr != nil {
return fmt.Errorf("Rotate StartLogger: %s\n", startLoggerErr)
return fmt.Errorf("Rotate StartLogger: %s", startLoggerErr)
}
if err != nil {
return fmt.Errorf("Rotate: %s\n", err)
return fmt.Errorf("Rotate: %s", err)
}
return nil
}
func (w *fileLogWriter) deleteOldLog() {
dir := filepath.Dir(w.Filename)
absolutePath, err := filepath.EvalSymlinks(w.Filename)
if err == nil {
dir = filepath.Dir(absolutePath)
}
filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) {
defer func() {
if r := recover(); r != nil {
@ -299,13 +373,21 @@ func (w *fileLogWriter) deleteOldLog() {
if info == nil {
return
}
if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
strings.HasSuffix(filepath.Base(path), w.suffix) {
os.Remove(path)
}
}
if w.Hourly {
if !info.IsDir() && info.ModTime().Add(1 * time.Hour * time.Duration(w.MaxHours)).Before(time.Now()) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
strings.HasSuffix(filepath.Base(path), w.suffix) {
os.Remove(path)
}
}
} else if w.Daily {
if !info.IsDir() && info.ModTime().Add(24 * time.Hour * time.Duration(w.MaxDays)).Before(time.Now()) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
strings.HasSuffix(filepath.Base(path), w.suffix) {
os.Remove(path)
}
}
}
return
})
}

View File

@ -112,7 +112,7 @@ func TestFile2(t *testing.T) {
os.Remove("test2.log")
}
func TestFileRotate_01(t *testing.T) {
func TestFileDailyRotate_01(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`)
log.Debug("debug")
@ -133,28 +133,28 @@ func TestFileRotate_01(t *testing.T) {
os.Remove("test3.log")
}
func TestFileRotate_02(t *testing.T) {
func TestFileDailyRotate_02(t *testing.T) {
fn1 := "rotate_day.log"
fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
testFileRotate(t, fn1, fn2)
fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log"
testFileRotate(t, fn1, fn2, true, false)
}
func TestFileRotate_03(t *testing.T) {
func TestFileDailyRotate_03(t *testing.T) {
fn1 := "rotate_day.log"
fn := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
os.Create(fn)
fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log"
testFileRotate(t, fn1, fn2)
testFileRotate(t, fn1, fn2, true, false)
os.Remove(fn)
}
func TestFileRotate_04(t *testing.T) {
func TestFileDailyRotate_04(t *testing.T) {
fn1 := "rotate_day.log"
fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log"
testFileDailyRotate(t, fn1, fn2)
}
func TestFileRotate_05(t *testing.T) {
func TestFileDailyRotate_05(t *testing.T) {
fn1 := "rotate_day.log"
fn := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
os.Create(fn)
@ -162,23 +162,131 @@ func TestFileRotate_05(t *testing.T) {
testFileDailyRotate(t, fn1, fn2)
os.Remove(fn)
}
func testFileRotate(t *testing.T, fn1, fn2 string) {
fw := &fileLogWriter{
Daily: true,
MaxDays: 7,
Rotate: true,
Level: LevelTrace,
Perm: "0660",
func TestFileDailyRotate_06(t *testing.T) { //test file mode
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`)
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log"
s, _ := os.Lstat(rotateName)
if s.Mode() != 0440 {
os.Remove(rotateName)
os.Remove("test3.log")
t.Fatal("rotate file mode error")
}
fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1))
fw.dailyOpenTime = time.Now().Add(-24 * time.Hour)
fw.dailyOpenDate = fw.dailyOpenTime.Day()
fw.WriteMsg(time.Now(), "this is a msg for test", LevelDebug)
os.Remove(rotateName)
os.Remove("test3.log")
}
func TestFileHourlyRotate_01(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test3.log","hourly":true,"maxlines":4}`)
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006010215"), 1) + ".log"
b, err := exists(rotateName)
if !b || err != nil {
os.Remove("test3.log")
t.Fatal("rotate not generated")
}
os.Remove(rotateName)
os.Remove("test3.log")
}
func TestFileHourlyRotate_02(t *testing.T) {
fn1 := "rotate_hour.log"
fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log"
testFileRotate(t, fn1, fn2, false, true)
}
func TestFileHourlyRotate_03(t *testing.T) {
fn1 := "rotate_hour.log"
fn := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".log"
os.Create(fn)
fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log"
testFileRotate(t, fn1, fn2, false, true)
os.Remove(fn)
}
func TestFileHourlyRotate_04(t *testing.T) {
fn1 := "rotate_hour.log"
fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log"
testFileHourlyRotate(t, fn1, fn2)
}
func TestFileHourlyRotate_05(t *testing.T) {
fn1 := "rotate_hour.log"
fn := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".log"
os.Create(fn)
fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log"
testFileHourlyRotate(t, fn1, fn2)
os.Remove(fn)
}
func TestFileHourlyRotate_06(t *testing.T) { //test file mode
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test3.log", "hourly":true, "maxlines":4}`)
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006010215"), 1) + ".log"
s, _ := os.Lstat(rotateName)
if s.Mode() != 0440 {
os.Remove(rotateName)
os.Remove("test3.log")
t.Fatal("rotate file mode error")
}
os.Remove(rotateName)
os.Remove("test3.log")
}
func testFileRotate(t *testing.T, fn1, fn2 string, daily, hourly bool) {
fw := &fileLogWriter{
Daily: daily,
MaxDays: 7,
Hourly: hourly,
MaxHours: 168,
Rotate: true,
Level: LevelTrace,
Perm: "0660",
RotatePerm: "0440",
}
if daily {
fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1))
fw.dailyOpenTime = time.Now().Add(-24 * time.Hour)
fw.dailyOpenDate = fw.dailyOpenTime.Day()
}
if hourly {
fw.Init(fmt.Sprintf(`{"filename":"%v","maxhours":1}`, fn1))
fw.hourlyOpenTime = time.Now().Add(-1 * time.Hour)
fw.hourlyOpenDate = fw.hourlyOpenTime.Day()
}
fw.WriteMsg(time.Now(), "this is a msg for test", LevelDebug)
for _, file := range []string{fn1, fn2} {
_, err := os.Stat(file)
if err != nil {
t.Log(err)
t.FailNow()
}
os.Remove(file)
@ -188,11 +296,12 @@ func testFileRotate(t *testing.T, fn1, fn2 string) {
func testFileDailyRotate(t *testing.T, fn1, fn2 string) {
fw := &fileLogWriter{
Daily: true,
MaxDays: 7,
Rotate: true,
Level: LevelTrace,
Perm: "0660",
Daily: true,
MaxDays: 7,
Rotate: true,
Level: LevelTrace,
Perm: "0660",
RotatePerm: "0440",
}
fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1))
fw.dailyOpenTime = time.Now().Add(-24 * time.Hour)
@ -217,6 +326,37 @@ func testFileDailyRotate(t *testing.T, fn1, fn2 string) {
fw.Destroy()
}
func testFileHourlyRotate(t *testing.T, fn1, fn2 string) {
fw := &fileLogWriter{
Hourly: true,
MaxHours: 168,
Rotate: true,
Level: LevelTrace,
Perm: "0660",
RotatePerm: "0440",
}
fw.Init(fmt.Sprintf(`{"filename":"%v","maxhours":1}`, fn1))
fw.hourlyOpenTime = time.Now().Add(-1 * time.Hour)
fw.hourlyOpenDate = fw.hourlyOpenTime.Hour()
hour, _ := time.ParseInLocation("2006010215", time.Now().Format("2006010215"), fw.hourlyOpenTime.Location())
hour = hour.Add(-1 * time.Second)
fw.hourlyRotate(hour)
for _, file := range []string{fn1, fn2} {
_, err := os.Stat(file)
if err != nil {
t.FailNow()
}
content, err := ioutil.ReadFile(file)
if err != nil {
t.FailNow()
}
if len(content) > 0 {
t.FailNow()
}
os.Remove(file)
}
fw.Destroy()
}
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {

View File

@ -25,11 +25,7 @@ func newJLWriter() Logger {
// Init JLWriter with json config string
func (s *JLWriter) Init(jsonconfig string) error {
err := json.Unmarshal([]byte(jsonconfig), s)
if err != nil {
return err
}
return nil
return json.Unmarshal([]byte(jsonconfig), s)
}
// WriteMsg write message in smtp writer.
@ -65,12 +61,10 @@ func (s *JLWriter) WriteMsg(when time.Time, msg string, level int) error {
// Flush implementing method. empty.
func (s *JLWriter) Flush() {
return
}
// Destroy implementing method. empty.
func (s *JLWriter) Destroy() {
return
}
func init() {

View File

@ -92,7 +92,7 @@ type Logger interface {
}
var adapters = make(map[string]newLoggerFunc)
var levelPrefix = [LevelDebug + 1]string{"[M] ", "[A] ", "[C] ", "[E] ", "[W] ", "[N] ", "[I] ", "[D] "}
var levelPrefix = [LevelDebug + 1]string{"[M]", "[A]", "[C]", "[E]", "[W]", "[N]", "[I]", "[D]"}
// Register makes a log provide available by the provided name.
// If Register is called twice with the same name or if driver is nil,
@ -116,6 +116,7 @@ type BeeLogger struct {
enableFuncCallDepth bool
loggerFuncCallDepth int
asynchronous bool
prefix string
msgChanLen int64
msgChan chan *logMsg
signalChan chan string
@ -186,12 +187,12 @@ func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error {
}
}
log, ok := adapters[adapterName]
logAdapter, ok := adapters[adapterName]
if !ok {
return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
}
lg := log()
lg := logAdapter()
err := lg.Init(config)
if err != nil {
fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
@ -267,6 +268,9 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error
if len(v) > 0 {
msg = fmt.Sprintf(msg, v...)
}
msg = bl.prefix + " " + msg
when := time.Now()
if bl.enableFuncCallDepth {
_, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
@ -275,7 +279,7 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error
line = 0
}
_, filename := path.Split(file)
msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "] " + msg
msg = "[" + filename + ":" + strconv.Itoa(line) + "] " + msg
}
//set level info in front of filename info
@ -283,7 +287,7 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error
// set to emergency to ensure all log will be print out correctly
logLevel = LevelEmergency
} else {
msg = levelPrefix[logLevel] + msg
msg = levelPrefix[logLevel] + " " + msg
}
if bl.asynchronous {
@ -291,7 +295,11 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error
lm.level = logLevel
lm.msg = msg
lm.when = when
bl.msgChan <- lm
if bl.outputs != nil {
bl.msgChan <- lm
} else {
logMsgPool.Put(lm)
}
} else {
bl.writeToLoggers(when, msg, logLevel)
}
@ -305,6 +313,11 @@ func (bl *BeeLogger) SetLevel(l int) {
bl.level = l
}
// GetLevel Get Current log message level.
func (bl *BeeLogger) GetLevel() int {
return bl.level
}
// SetLogFuncCallDepth set log funcCallDepth
func (bl *BeeLogger) SetLogFuncCallDepth(d int) {
bl.loggerFuncCallDepth = d
@ -320,6 +333,11 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
bl.enableFuncCallDepth = b
}
// set prefix
func (bl *BeeLogger) SetPrefix(s string) {
bl.prefix = s
}
// start logger chan reading.
// when chan is not empty, write logs.
func (bl *BeeLogger) startLogger() {
@ -492,9 +510,9 @@ func (bl *BeeLogger) flush() {
}
// beeLogger references the used application logger.
var beeLogger *BeeLogger = NewLogger()
var beeLogger = NewLogger()
// GetLogger returns the default BeeLogger
// GetBeeLogger returns the default BeeLogger
func GetBeeLogger() *BeeLogger {
return beeLogger
}
@ -534,6 +552,7 @@ func Reset() {
beeLogger.Reset()
}
// Async set the beelogger with Async mode and hold msglen messages
func Async(msgLen ...int64) *BeeLogger {
return beeLogger.Async(msgLen...)
}
@ -543,6 +562,11 @@ func SetLevel(l int) {
beeLogger.SetLevel(l)
}
// SetPrefix sets the prefix
func SetPrefix(s string) {
beeLogger.SetPrefix(s)
}
// EnableFuncCallDepth enable log funcCallDepth
func EnableFuncCallDepth(b bool) {
beeLogger.enableFuncCallDepth = b
@ -561,11 +585,7 @@ func SetLogFuncCallDepth(d int) {
// SetLogger sets a new logger.
func SetLogger(adapter string, config ...string) error {
err := beeLogger.SetLogger(adapter, config...)
if err != nil {
return err
}
return nil
return beeLogger.SetLogger(adapter, config...)
}
// Emergency logs a message at emergency level.

View File

@ -15,9 +15,8 @@
package logs
import (
"fmt"
"io"
"os"
"runtime"
"sync"
"time"
)
@ -31,47 +30,13 @@ func newLogWriter(wr io.Writer) *logWriter {
return &logWriter{writer: wr}
}
func (lg *logWriter) println(when time.Time, msg string) {
func (lg *logWriter) writeln(when time.Time, msg string) {
lg.Lock()
h, _ := formatTimeHeader(when)
h, _, _ := formatTimeHeader(when)
lg.writer.Write(append(append(h, msg...), '\n'))
lg.Unlock()
}
type outputMode int
// DiscardNonColorEscSeq supports the divided color escape sequence.
// But non-color escape sequence is not output.
// Please use the OutputNonColorEscSeq If you want to output a non-color
// escape sequences such as ncurses. However, it does not support the divided
// color escape sequence.
const (
_ outputMode = iota
DiscardNonColorEscSeq
OutputNonColorEscSeq
)
// NewAnsiColorWriter creates and initializes a new ansiColorWriter
// using io.Writer w as its initial contents.
// In the console of Windows, which change the foreground and background
// colors of the text by the escape sequence.
// In the console of other systems, which writes to w all text.
func NewAnsiColorWriter(w io.Writer) io.Writer {
return NewModeAnsiColorWriter(w, DiscardNonColorEscSeq)
}
// NewModeAnsiColorWriter create and initializes a new ansiColorWriter
// by specifying the outputMode.
func NewModeAnsiColorWriter(w io.Writer, mode outputMode) io.Writer {
if _, ok := w.(*ansiColorWriter); !ok {
return &ansiColorWriter{
w: w,
mode: mode,
}
}
return w
}
const (
y1 = `0123456789`
y2 = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789`
@ -87,13 +52,15 @@ const (
mi2 = `012345678901234567890123456789012345678901234567890123456789`
s1 = `000000000011111111112222222222333333333344444444445555555555`
s2 = `012345678901234567890123456789012345678901234567890123456789`
ns1 = `0123456789`
)
func formatTimeHeader(when time.Time) ([]byte, int) {
func formatTimeHeader(when time.Time) ([]byte, int, int) {
y, mo, d := when.Date()
h, mi, s := when.Clock()
//len("2006/01/02 15:04:05 ")==20
var buf [20]byte
ns := when.Nanosecond() / 1000000
//len("2006/01/02 15:04:05.123 ")==24
var buf [24]byte
buf[0] = y1[y/1000%10]
buf[1] = y2[y/100]
@ -114,9 +81,14 @@ func formatTimeHeader(when time.Time) ([]byte, int) {
buf[16] = ':'
buf[17] = s1[s]
buf[18] = s2[s]
buf[19] = ' '
buf[19] = '.'
buf[20] = ns1[ns/100]
buf[21] = ns1[ns%100/10]
buf[22] = ns1[ns%10]
return buf[0:], d
buf[23] = ' '
return buf[0:], d, h
}
var (
@ -139,50 +111,65 @@ var (
reset = string([]byte{27, 91, 48, 109})
)
func ColorByStatus(cond bool, code int) string {
var once sync.Once
var colorMap map[string]string
func initColor() {
if runtime.GOOS == "windows" {
green = w32Green
white = w32White
yellow = w32Yellow
red = w32Red
blue = w32Blue
magenta = w32Magenta
cyan = w32Cyan
}
colorMap = map[string]string{
//by color
"green": green,
"white": white,
"yellow": yellow,
"red": red,
//by method
"GET": blue,
"POST": cyan,
"PUT": yellow,
"DELETE": red,
"PATCH": green,
"HEAD": magenta,
"OPTIONS": white,
}
}
// ColorByStatus return color by http code
// 2xx return Green
// 3xx return White
// 4xx return Yellow
// 5xx return Red
func ColorByStatus(code int) string {
once.Do(initColor)
switch {
case code >= 200 && code < 300:
return map[bool]string{true: green, false: w32Green}[cond]
return colorMap["green"]
case code >= 300 && code < 400:
return map[bool]string{true: white, false: w32White}[cond]
return colorMap["white"]
case code >= 400 && code < 500:
return map[bool]string{true: yellow, false: w32Yellow}[cond]
return colorMap["yellow"]
default:
return map[bool]string{true: red, false: w32Red}[cond]
return colorMap["red"]
}
}
func ColorByMethod(cond bool, method string) string {
switch method {
case "GET":
return map[bool]string{true: blue, false: w32Blue}[cond]
case "POST":
return map[bool]string{true: cyan, false: w32Cyan}[cond]
case "PUT":
return map[bool]string{true: yellow, false: w32Yellow}[cond]
case "DELETE":
return map[bool]string{true: red, false: w32Red}[cond]
case "PATCH":
return map[bool]string{true: green, false: w32Green}[cond]
case "HEAD":
return map[bool]string{true: magenta, false: w32Magenta}[cond]
case "OPTIONS":
return map[bool]string{true: white, false: w32White}[cond]
default:
return reset
// ColorByMethod return color by http code
func ColorByMethod(method string) string {
once.Do(initColor)
if c := colorMap[method]; c != "" {
return c
}
return reset
}
// Guard Mutex to guarantee atomicity of W32Debug(string) function
var mu sync.Mutex
// Helper method to output colored logs in Windows terminals
func W32Debug(msg string) {
mu.Lock()
defer mu.Unlock()
current := time.Now()
w := NewAnsiColorWriter(os.Stdout)
fmt.Fprintf(w, "[beego] %v %s\n", current.Format("2006/01/02 - 15:04:05"), msg)
// ResetColor return reset color
func ResetColor() string {
return reset
}

View File

@ -15,7 +15,6 @@
package logs
import (
"bytes"
"testing"
"time"
)
@ -30,8 +29,8 @@ func TestFormatHeader_0(t *testing.T) {
if tm.Year() >= 2100 {
break
}
h, _ := formatTimeHeader(tm)
if tm.Format("2006/01/02 15:04:05 ") != string(h) {
h, _, _ := formatTimeHeader(tm)
if tm.Format("2006/01/02 15:04:05.000 ") != string(h) {
t.Log(tm)
t.FailNow()
}
@ -48,28 +47,11 @@ func TestFormatHeader_1(t *testing.T) {
if tm.Year() >= year+1 {
break
}
h, _ := formatTimeHeader(tm)
if tm.Format("2006/01/02 15:04:05 ") != string(h) {
h, _, _ := formatTimeHeader(tm)
if tm.Format("2006/01/02 15:04:05.000 ") != string(h) {
t.Log(tm)
t.FailNow()
}
tm = tm.Add(dur)
}
}
func TestNewAnsiColor1(t *testing.T) {
inner := bytes.NewBufferString("")
w := NewAnsiColorWriter(inner)
if w == inner {
t.Errorf("Get %#v, want %#v", w, inner)
}
}
func TestNewAnsiColor2(t *testing.T) {
inner := bytes.NewBufferString("")
w1 := NewAnsiColorWriter(inner)
w2 := NewAnsiColorWriter(w1)
if w1 != w2 {
t.Errorf("Get %#v, want %#v", w1, w2)
}
}

View File

@ -67,7 +67,10 @@ func (f *multiFileLogWriter) Init(config string) error {
jsonMap["level"] = i
bs, _ := json.Marshal(jsonMap)
writer = newFileWriter().(*fileLogWriter)
writer.Init(string(bs))
err := writer.Init(string(bs))
if err != nil {
return err
}
f.writers[i] = writer
}
}

View File

@ -21,11 +21,7 @@ func newSLACKWriter() Logger {
// Init SLACKWriter with json config string
func (s *SLACKWriter) Init(jsonconfig string) error {
err := json.Unmarshal([]byte(jsonconfig), s)
if err != nil {
return err
}
return nil
return json.Unmarshal([]byte(jsonconfig), s)
}
// WriteMsg write message in smtp writer.
@ -53,12 +49,10 @@ func (s *SLACKWriter) WriteMsg(when time.Time, msg string, level int) error {
// Flush implementing method. empty.
func (s *SLACKWriter) Flush() {
return
}
// Destroy implementing method. empty.
func (s *SLACKWriter) Destroy() {
return
}
func init() {

View File

@ -52,11 +52,7 @@ func newSMTPWriter() Logger {
// "level":LevelError
// }
func (s *SMTPWriter) Init(jsonconfig string) error {
err := json.Unmarshal([]byte(jsonconfig), s)
if err != nil {
return err
}
return nil
return json.Unmarshal([]byte(jsonconfig), s)
}
func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth {
@ -106,7 +102,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd
if err != nil {
return err
}
_, err = w.Write([]byte(msgContent))
_, err = w.Write(msgContent)
if err != nil {
return err
}
@ -116,12 +112,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd
return err
}
err = client.Quit()
if err != nil {
return err
}
return nil
return client.Quit()
}
// WriteMsg write message in smtp writer.
@ -147,12 +138,10 @@ func (s *SMTPWriter) WriteMsg(when time.Time, msg string, level int) error {
// Flush implementing method. empty.
func (s *SMTPWriter) Flush() {
return
}
// Destroy implementing method. empty.
func (s *SMTPWriter) Destroy() {
return
}
func init() {

99
metric/prometheus.go Normal file
View File

@ -0,0 +1,99 @@
// Copyright 2020 astaxie
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package metric
import (
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
)
func PrometheusMiddleWare(next http.Handler) http.Handler {
summaryVec := prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: "beego",
Subsystem: "http_request",
ConstLabels: map[string]string{
"server": beego.BConfig.ServerName,
"env": beego.BConfig.RunMode,
"appname": beego.BConfig.AppName,
},
Help: "The statics info for http request",
}, []string{"pattern", "method", "status", "duration"})
prometheus.MustRegister(summaryVec)
registerBuildInfo()
return http.HandlerFunc(func(writer http.ResponseWriter, q *http.Request) {
start := time.Now()
next.ServeHTTP(writer, q)
end := time.Now()
go report(end.Sub(start), writer, q, summaryVec)
})
}
func registerBuildInfo() {
buildInfo := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "beego",
Subsystem: "build_info",
Help: "The building information",
ConstLabels: map[string]string{
"appname": beego.BConfig.AppName,
"build_version": beego.BuildVersion,
"build_revision": beego.BuildGitRevision,
"build_status": beego.BuildStatus,
"build_tag": beego.BuildTag,
"build_time": strings.Replace(beego.BuildTime, "--", " ", 1),
"go_version": beego.GoVersion,
"git_branch": beego.GitBranch,
"start_time": time.Now().Format("2006-01-02 15:04:05"),
},
}, []string{})
prometheus.MustRegister(buildInfo)
buildInfo.WithLabelValues().Set(1)
}
func report(dur time.Duration, writer http.ResponseWriter, q *http.Request, vec *prometheus.SummaryVec) {
ctrl := beego.BeeApp.Handlers
ctx := ctrl.GetContext()
ctx.Reset(writer, q)
defer ctrl.GiveBackContext(ctx)
// We cannot read the status code from q.Response.StatusCode
// since the http server does not set q.Response. So q.Response is nil
// Thus, we use reflection to read the status from writer whose concrete type is http.response
responseVal := reflect.ValueOf(writer).Elem()
field := responseVal.FieldByName("status")
status := -1
if field.IsValid() && field.Kind() == reflect.Int {
status = int(field.Int())
}
ptn := "UNKNOWN"
if rt, found := ctrl.FindRouter(ctx); found {
ptn = rt.GetPattern()
} else {
logs.Warn("we can not find the router info for this request, so request will be recorded as UNKNOWN: " + q.URL.String())
}
ms := dur / time.Millisecond
vec.WithLabelValues(ptn, q.Method, strconv.Itoa(status), strconv.Itoa(int(ms))).Observe(float64(ms))
}

42
metric/prometheus_test.go Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2020 astaxie
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package metric
import (
"net/http"
"net/url"
"testing"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/astaxie/beego/context"
)
func TestPrometheusMiddleWare(t *testing.T) {
middleware := PrometheusMiddleWare(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
writer := &context.Response{}
request := &http.Request{
URL: &url.URL{
Host: "localhost",
RawPath: "/a/b/c",
},
Method: "POST",
}
vec := prometheus.NewSummaryVec(prometheus.SummaryOpts{}, []string{"pattern", "method", "status", "duration"})
report(time.Second, writer, request, vec)
middleware.ServeHTTP(writer, request)
}

View File

@ -14,40 +14,382 @@
package migration
// Table store the tablename and Column
type Table struct {
TableName string
Columns []*Column
import (
"fmt"
"github.com/astaxie/beego/logs"
)
// Index struct defines the structure of Index Columns
type Index struct {
Name string
}
// Create return the create sql
func (t *Table) Create() string {
return ""
// Unique struct defines a single unique key combination
type Unique struct {
Definition string
Columns []*Column
}
// Drop return the drop sql
func (t *Table) Drop() string {
return ""
}
// Column define the columns name type and Default
//Column struct defines a single column of a table
type Column struct {
Name string
Type string
Default interface{}
Name string
Inc string
Null string
Default string
Unsign string
DataType string
remove bool
Modify bool
}
// Create return create sql with the provided tbname and columns
func Create(tbname string, columns ...Column) string {
return ""
// Foreign struct defines a single foreign relationship
type Foreign struct {
ForeignTable string
ForeignColumn string
OnDelete string
OnUpdate string
Column
}
// Drop return the drop sql with the provided tbname and columns
func Drop(tbname string, columns ...Column) string {
return ""
// RenameColumn struct allows renaming of columns
type RenameColumn struct {
OldName string
OldNull string
OldDefault string
OldUnsign string
OldDataType string
NewName string
Column
}
// TableDDL is still in think
func TableDDL(tbname string, columns ...Column) string {
return ""
// CreateTable creates the table on system
func (m *Migration) CreateTable(tablename, engine, charset string, p ...func()) {
m.TableName = tablename
m.Engine = engine
m.Charset = charset
m.ModifyType = "create"
}
// AlterTable set the ModifyType to alter
func (m *Migration) AlterTable(tablename string) {
m.TableName = tablename
m.ModifyType = "alter"
}
// NewCol creates a new standard column and attaches it to m struct
func (m *Migration) NewCol(name string) *Column {
col := &Column{Name: name}
m.AddColumns(col)
return col
}
//PriCol creates a new primary column and attaches it to m struct
func (m *Migration) PriCol(name string) *Column {
col := &Column{Name: name}
m.AddColumns(col)
m.AddPrimary(col)
return col
}
//UniCol creates / appends columns to specified unique key and attaches it to m struct
func (m *Migration) UniCol(uni, name string) *Column {
col := &Column{Name: name}
m.AddColumns(col)
uniqueOriginal := &Unique{}
for _, unique := range m.Uniques {
if unique.Definition == uni {
unique.AddColumnsToUnique(col)
uniqueOriginal = unique
}
}
if uniqueOriginal.Definition == "" {
unique := &Unique{Definition: uni}
unique.AddColumnsToUnique(col)
m.AddUnique(unique)
}
return col
}
//ForeignCol creates a new foreign column and returns the instance of column
func (m *Migration) ForeignCol(colname, foreigncol, foreigntable string) (foreign *Foreign) {
foreign = &Foreign{ForeignColumn: foreigncol, ForeignTable: foreigntable}
foreign.Name = colname
m.AddForeign(foreign)
return foreign
}
//SetOnDelete sets the on delete of foreign
func (foreign *Foreign) SetOnDelete(del string) *Foreign {
foreign.OnDelete = "ON DELETE" + del
return foreign
}
//SetOnUpdate sets the on update of foreign
func (foreign *Foreign) SetOnUpdate(update string) *Foreign {
foreign.OnUpdate = "ON UPDATE" + update
return foreign
}
//Remove marks the columns to be removed.
//it allows reverse m to create the column.
func (c *Column) Remove() {
c.remove = true
}
//SetAuto enables auto_increment of column (can be used once)
func (c *Column) SetAuto(inc bool) *Column {
if inc {
c.Inc = "auto_increment"
}
return c
}
//SetNullable sets the column to be null
func (c *Column) SetNullable(null bool) *Column {
if null {
c.Null = ""
} else {
c.Null = "NOT NULL"
}
return c
}
//SetDefault sets the default value, prepend with "DEFAULT "
func (c *Column) SetDefault(def string) *Column {
c.Default = "DEFAULT " + def
return c
}
//SetUnsigned sets the column to be unsigned int
func (c *Column) SetUnsigned(unsign bool) *Column {
if unsign {
c.Unsign = "UNSIGNED"
}
return c
}
//SetDataType sets the dataType of the column
func (c *Column) SetDataType(dataType string) *Column {
c.DataType = dataType
return c
}
//SetOldNullable allows reverting to previous nullable on reverse ms
func (c *RenameColumn) SetOldNullable(null bool) *RenameColumn {
if null {
c.OldNull = ""
} else {
c.OldNull = "NOT NULL"
}
return c
}
//SetOldDefault allows reverting to previous default on reverse ms
func (c *RenameColumn) SetOldDefault(def string) *RenameColumn {
c.OldDefault = def
return c
}
//SetOldUnsigned allows reverting to previous unsgined on reverse ms
func (c *RenameColumn) SetOldUnsigned(unsign bool) *RenameColumn {
if unsign {
c.OldUnsign = "UNSIGNED"
}
return c
}
//SetOldDataType allows reverting to previous datatype on reverse ms
func (c *RenameColumn) SetOldDataType(dataType string) *RenameColumn {
c.OldDataType = dataType
return c
}
//SetPrimary adds the columns to the primary key (can only be used any number of times in only one m)
func (c *Column) SetPrimary(m *Migration) *Column {
m.Primary = append(m.Primary, c)
return c
}
//AddColumnsToUnique adds the columns to Unique Struct
func (unique *Unique) AddColumnsToUnique(columns ...*Column) *Unique {
unique.Columns = append(unique.Columns, columns...)
return unique
}
//AddColumns adds columns to m struct
func (m *Migration) AddColumns(columns ...*Column) *Migration {
m.Columns = append(m.Columns, columns...)
return m
}
//AddPrimary adds the column to primary in m struct
func (m *Migration) AddPrimary(primary *Column) *Migration {
m.Primary = append(m.Primary, primary)
return m
}
//AddUnique adds the column to unique in m struct
func (m *Migration) AddUnique(unique *Unique) *Migration {
m.Uniques = append(m.Uniques, unique)
return m
}
//AddForeign adds the column to foreign in m struct
func (m *Migration) AddForeign(foreign *Foreign) *Migration {
m.Foreigns = append(m.Foreigns, foreign)
return m
}
//AddIndex adds the column to index in m struct
func (m *Migration) AddIndex(index *Index) *Migration {
m.Indexes = append(m.Indexes, index)
return m
}
//RenameColumn allows renaming of columns
func (m *Migration) RenameColumn(from, to string) *RenameColumn {
rename := &RenameColumn{OldName: from, NewName: to}
m.Renames = append(m.Renames, rename)
return rename
}
//GetSQL returns the generated sql depending on ModifyType
func (m *Migration) GetSQL() (sql string) {
sql = ""
switch m.ModifyType {
case "create":
{
sql += fmt.Sprintf("CREATE TABLE `%s` (", m.TableName)
for index, column := range m.Columns {
sql += fmt.Sprintf("\n `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
if len(m.Columns) > index+1 {
sql += ","
}
}
if len(m.Primary) > 0 {
sql += fmt.Sprintf(",\n PRIMARY KEY( ")
}
for index, column := range m.Primary {
sql += fmt.Sprintf(" `%s`", column.Name)
if len(m.Primary) > index+1 {
sql += ","
}
}
if len(m.Primary) > 0 {
sql += fmt.Sprintf(")")
}
for _, unique := range m.Uniques {
sql += fmt.Sprintf(",\n UNIQUE KEY `%s`( ", unique.Definition)
for index, column := range unique.Columns {
sql += fmt.Sprintf(" `%s`", column.Name)
if len(unique.Columns) > index+1 {
sql += ","
}
}
sql += fmt.Sprintf(")")
}
for _, foreign := range m.Foreigns {
sql += fmt.Sprintf(",\n `%s` %s %s %s %s %s", foreign.Name, foreign.DataType, foreign.Unsign, foreign.Null, foreign.Inc, foreign.Default)
sql += fmt.Sprintf(",\n KEY `%s_%s_foreign`(`%s`),", m.TableName, foreign.Column.Name, foreign.Column.Name)
sql += fmt.Sprintf("\n CONSTRAINT `%s_%s_foreign` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) %s %s", m.TableName, foreign.Column.Name, foreign.Column.Name, foreign.ForeignTable, foreign.ForeignColumn, foreign.OnDelete, foreign.OnUpdate)
}
sql += fmt.Sprintf(")ENGINE=%s DEFAULT CHARSET=%s;", m.Engine, m.Charset)
break
}
case "alter":
{
sql += fmt.Sprintf("ALTER TABLE `%s` ", m.TableName)
for index, column := range m.Columns {
if !column.remove {
logs.Info("col")
sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
} else {
sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name)
}
if len(m.Columns) > index+1 {
sql += ","
}
}
for index, column := range m.Renames {
sql += fmt.Sprintf("CHANGE COLUMN `%s` `%s` %s %s %s %s %s", column.OldName, column.NewName, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
if len(m.Renames) > index+1 {
sql += ","
}
}
for index, foreign := range m.Foreigns {
sql += fmt.Sprintf("ADD `%s` %s %s %s %s %s", foreign.Name, foreign.DataType, foreign.Unsign, foreign.Null, foreign.Inc, foreign.Default)
sql += fmt.Sprintf(",\n ADD KEY `%s_%s_foreign`(`%s`)", m.TableName, foreign.Column.Name, foreign.Column.Name)
sql += fmt.Sprintf(",\n ADD CONSTRAINT `%s_%s_foreign` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) %s %s", m.TableName, foreign.Column.Name, foreign.Column.Name, foreign.ForeignTable, foreign.ForeignColumn, foreign.OnDelete, foreign.OnUpdate)
if len(m.Foreigns) > index+1 {
sql += ","
}
}
sql += ";"
break
}
case "reverse":
{
sql += fmt.Sprintf("ALTER TABLE `%s`", m.TableName)
for index, column := range m.Columns {
if column.remove {
sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
} else {
sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name)
}
if len(m.Columns) > index+1 {
sql += ","
}
}
if len(m.Primary) > 0 {
sql += fmt.Sprintf("\n DROP PRIMARY KEY,")
}
for index, unique := range m.Uniques {
sql += fmt.Sprintf("\n DROP KEY `%s`", unique.Definition)
if len(m.Uniques) > index+1 {
sql += ","
}
}
for index, column := range m.Renames {
sql += fmt.Sprintf("\n CHANGE COLUMN `%s` `%s` %s %s %s %s", column.NewName, column.OldName, column.OldDataType, column.OldUnsign, column.OldNull, column.OldDefault)
if len(m.Renames) > index+1 {
sql += ","
}
}
for _, foreign := range m.Foreigns {
sql += fmt.Sprintf("\n DROP KEY `%s_%s_foreign`", m.TableName, foreign.Column.Name)
sql += fmt.Sprintf(",\n DROP FOREIGN KEY `%s_%s_foreign`", m.TableName, foreign.Column.Name)
sql += fmt.Sprintf(",\n DROP COLUMN `%s`", foreign.Name)
}
sql += ";"
}
case "delete":
{
sql += fmt.Sprintf("DROP TABLE IF EXISTS `%s`;", m.TableName)
}
}
return
}

32
migration/doc.go Normal file
View File

@ -0,0 +1,32 @@
// Package migration enables you to generate migrations back and forth. It generates both migrations.
//
// //Creates a table
// m.CreateTable("tablename","InnoDB","utf8");
//
// //Alter a table
// m.AlterTable("tablename")
//
// Standard Column Methods
// * SetDataType
// * SetNullable
// * SetDefault
// * SetUnsigned (use only on integer types unless produces error)
//
// //Sets a primary column, multiple calls allowed, standard column methods available
// m.PriCol("id").SetAuto(true).SetNullable(false).SetDataType("INT(10)").SetUnsigned(true)
//
// //UniCol Can be used multiple times, allows standard Column methods. Use same "index" string to add to same index
// m.UniCol("index","column")
//
// //Standard Column Initialisation, can call .Remove() after NewCol("") on alter to remove
// m.NewCol("name").SetDataType("VARCHAR(255) COLLATE utf8_unicode_ci").SetNullable(false)
// m.NewCol("value").SetDataType("DOUBLE(8,2)").SetNullable(false)
//
// //Rename Columns , only use with Alter table, doesn't works with Create, prefix standard column methods with "Old" to
// //create a true reversible migration eg: SetOldDataType("DOUBLE(12,3)")
// m.RenameColumn("from","to")...
//
// //Foreign Columns, single columns are only supported, SetOnDelete & SetOnUpdate are available, call appropriately.
// //Supports standard column methods, automatic reverse.
// m.ForeignCol("local_col","foreign_col","foreign_table")
package migration

View File

@ -52,6 +52,26 @@ type Migrationer interface {
GetCreated() int64
}
//Migration defines the migrations by either SQL or DDL
type Migration struct {
sqls []string
Created string
TableName string
Engine string
Charset string
ModifyType string
Columns []*Column
Indexes []*Index
Primary []*Column
Uniques []*Unique
Foreigns []*Foreign
Renames []*RenameColumn
RemoveColumns []*Column
RemoveIndexes []*Index
RemoveUniques []*Unique
RemoveForeigns []*Foreign
}
var (
migrationMap map[string]Migrationer
)
@ -60,20 +80,34 @@ func init() {
migrationMap = make(map[string]Migrationer)
}
// Migration the basic type which will implement the basic type
type Migration struct {
sqls []string
Created string
}
// Up implement in the Inheritance struct for upgrade
func (m *Migration) Up() {
switch m.ModifyType {
case "reverse":
m.ModifyType = "alter"
case "delete":
m.ModifyType = "create"
}
m.sqls = append(m.sqls, m.GetSQL())
}
// Down implement in the Inheritance struct for down
func (m *Migration) Down() {
switch m.ModifyType {
case "alter":
m.ModifyType = "reverse"
case "create":
m.ModifyType = "delete"
}
m.sqls = append(m.sqls, m.GetSQL())
}
//Migrate adds the SQL to the execution list
func (m *Migration) Migrate(migrationType string) {
m.ModifyType = migrationType
m.sqls = append(m.sqls, m.GetSQL())
}
// SQL add sql want to execute
@ -138,12 +172,13 @@ func Register(name string, m Migrationer) error {
return nil
}
// Upgrade upgrate the migration from lasttime
// Upgrade upgrade the migration from lasttime
func Upgrade(lasttime int64) error {
sm := sortMap(migrationMap)
i := 0
migs, _ := getAllMigrations()
for _, v := range sm {
if v.created > lasttime {
if _, ok := migs[v.name]; !ok {
logs.Info("start upgrade", v.name)
v.m.Reset()
v.m.Up()
@ -276,3 +311,20 @@ func isRollBack(name string) bool {
}
return false
}
func getAllMigrations() (map[string]string, error) {
o := orm.NewOrm()
var maps []orm.Params
migs := make(map[string]string)
num, err := o.Raw("select * from migrations order by id_migration desc").Values(&maps)
if err != nil {
logs.Info("get name has error", err)
return migs, err
}
if num > 0 {
for _, v := range maps {
name := v["name"].(string)
migs[name] = v["status"].(string)
}
}
return migs, nil
}

View File

@ -207,11 +207,11 @@ func (n *Namespace) Include(cList ...ControllerInterface) *Namespace {
func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
for _, ni := range ns {
for k, v := range ni.handlers.routers {
if t, ok := n.handlers.routers[k]; ok {
if _, ok := n.handlers.routers[k]; ok {
addPrefix(v, ni.prefix)
n.handlers.routers[k].AddTree(ni.prefix, v)
} else {
t = NewTree()
t := NewTree()
t.AddTree(ni.prefix, v)
addPrefix(t, ni.prefix)
n.handlers.routers[k] = t
@ -236,11 +236,11 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
func AddNamespace(nl ...*Namespace) {
for _, n := range nl {
for k, v := range n.handlers.routers {
if t, ok := BeeApp.Handlers.routers[k]; ok {
if _, ok := BeeApp.Handlers.routers[k]; ok {
addPrefix(v, n.prefix)
BeeApp.Handlers.routers[k].AddTree(n.prefix, v)
} else {
t = NewTree()
t := NewTree()
t.AddTree(n.prefix, v)
addPrefix(t, n.prefix)
BeeApp.Handlers.routers[k] = t
@ -267,13 +267,12 @@ func addPrefix(t *Tree, prefix string) {
addPrefix(t.wildcard, prefix)
}
for _, l := range t.leaves {
if c, ok := l.runObject.(*controllerInfo); ok {
if c, ok := l.runObject.(*ControllerInfo); ok {
if !strings.HasPrefix(c.pattern, prefix) {
c.pattern = prefix + c.pattern
}
}
}
}
// NSCond is Namespace Condition
@ -284,16 +283,16 @@ func NSCond(cond namespaceCond) LinkNamespace {
}
// NSBefore Namespace BeforeRouter filter
func NSBefore(filiterList ...FilterFunc) LinkNamespace {
func NSBefore(filterList ...FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Filter("before", filiterList...)
ns.Filter("before", filterList...)
}
}
// NSAfter add Namespace FinishRouter filter
func NSAfter(filiterList ...FilterFunc) LinkNamespace {
func NSAfter(filterList ...FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Filter("after", filiterList...)
ns.Filter("after", filterList...)
}
}

View File

@ -139,10 +139,7 @@ func TestNamespaceCond(t *testing.T) {
ns := NewNamespace("/v2")
ns.Cond(func(ctx *context.Context) bool {
if ctx.Input.Domain() == "beego.me" {
return true
}
return false
return ctx.Input.Domain() == "beego.me"
}).
AutoRouter(&TestController{})
AddNamespace(ns)

View File

@ -61,6 +61,9 @@ func init() {
// set default database
orm.RegisterDataBase("default", "mysql", "root:root@/my_db?charset=utf8", 30)
// create table
orm.RunSyncdb("default", false, true)
}
func main() {

View File

@ -150,7 +150,7 @@ func (d *commandSyncDb) Run() error {
}
for _, fi := range mi.fields.fieldsDB {
if _, ok := columns[fi.column]; ok == false {
if _, ok := columns[fi.column]; !ok {
fields = append(fields, fi)
}
}
@ -175,7 +175,7 @@ func (d *commandSyncDb) Run() error {
}
for _, idx := range indexes[mi.table] {
if d.al.DbBaser.IndexExists(db, idx.Table, idx.Name) == false {
if !d.al.DbBaser.IndexExists(db, idx.Table, idx.Name) {
if !d.noInfo {
fmt.Printf("create index `%s` for table `%s`\n", idx.Name, idx.Table)
}

View File

@ -51,12 +51,14 @@ checkColumn:
switch fieldType {
case TypeBooleanField:
col = T["bool"]
case TypeCharField:
case TypeVarCharField:
if al.Driver == DRPostgres && fi.toText {
col = T["string-text"]
} else {
col = fmt.Sprintf(T["string"], fieldSize)
}
case TypeCharField:
col = fmt.Sprintf(T["string-char"], fieldSize)
case TypeTextField:
col = T["string-text"]
case TypeTimeField:
@ -89,20 +91,20 @@ checkColumn:
col = T["float64"]
case TypeDecimalField:
s := T["float64-decimal"]
if strings.Index(s, "%d") == -1 {
if !strings.Contains(s, "%d") {
col = s
} else {
col = fmt.Sprintf(s, fi.digits, fi.decimals)
}
case TypeJSONField:
if al.Driver != DRPostgres {
fieldType = TypeCharField
fieldType = TypeVarCharField
goto checkColumn
}
col = T["json"]
case TypeJsonbField:
if al.Driver != DRPostgres {
fieldType = TypeCharField
fieldType = TypeVarCharField
goto checkColumn
}
col = T["jsonb"]
@ -120,7 +122,7 @@ func getColumnAddQuery(al *alias, fi *fieldInfo) string {
Q := al.DbBaser.TableQuote()
typ := getColumnTyp(al, fi)
if fi.null == false {
if !fi.null {
typ += " " + "NOT NULL"
}
@ -172,7 +174,7 @@ func getDbCreateSQL(al *alias) (sqls []string, tableIndexes map[string][]dbIndex
} else {
column += col
if fi.null == false {
if !fi.null {
column += " " + "NOT NULL"
}
@ -192,9 +194,13 @@ func getDbCreateSQL(al *alias) (sqls []string, tableIndexes map[string][]dbIndex
}
}
if strings.Index(column, "%COL%") != -1 {
if strings.Contains(column, "%COL%") {
column = strings.Replace(column, "%COL%", fi.column, -1)
}
if fi.description != "" && al.Driver!=DRSqlite {
column += " " + fmt.Sprintf("COMMENT '%s'",fi.description)
}
columns = append(columns, column)
}

145
orm/db.go
View File

@ -48,7 +48,7 @@ var (
"lte": true,
"eq": true,
"nq": true,
"ne": true,
"ne": true,
"startswith": true,
"endswith": true,
"istartswith": true,
@ -87,7 +87,7 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string,
} else {
panic(fmt.Errorf("wrong db field/column name `%s` for model `%s`", column, mi.fullName))
}
if fi.dbcol == false || fi.auto && skipAuto {
if !fi.dbcol || fi.auto && skipAuto {
continue
}
value, err := d.collectFieldValue(mi, fi, ind, insert, tz)
@ -142,7 +142,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
} else {
value = field.Bool()
}
case TypeCharField, TypeTextField, TypeJSONField, TypeJsonbField:
case TypeVarCharField, TypeCharField, TypeTextField, TypeJSONField, TypeJsonbField:
if ns, ok := field.Interface().(sql.NullString); ok {
value = nil
if ns.Valid {
@ -224,7 +224,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
value = nil
}
}
if fi.null == false && value == nil {
if !fi.null && value == nil {
return nil, fmt.Errorf("field `%s` cannot be NULL", fi.fullName)
}
}
@ -271,7 +271,7 @@ func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string,
dbcols := make([]string, 0, len(mi.fields.dbcols))
marks := make([]string, 0, len(mi.fields.dbcols))
for _, fi := range mi.fields.fieldsDB {
if fi.auto == false {
if !fi.auto {
dbcols = append(dbcols, fi.column)
marks = append(marks, "?")
}
@ -326,7 +326,7 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo
} else {
// default use pk value as where condtion.
pkColumn, pkValue, ok := getExistPk(mi, ind)
if ok == false {
if !ok {
return ErrMissPK
}
whereCols = []string{pkColumn}
@ -470,7 +470,7 @@ func (d *dbBase) InsertValue(q dbQuerier, mi *modelInfo, isMulti bool, names []s
multi := len(values) / len(names)
if isMulti {
if isMulti && multi > 1 {
qmarks = strings.Repeat(qmarks+"), (", multi-1) + qmarks
}
@ -507,10 +507,9 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a
case DRPostgres:
if len(args) == 0 {
return 0, fmt.Errorf("`%s` use InsertOrUpdate must have a conflict column", a.DriverName)
} else {
args0 = strings.ToLower(args[0])
iouStr = fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET", args0)
}
args0 = strings.ToLower(args[0])
iouStr = fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET", args0)
default:
return 0, fmt.Errorf("`%s` nonsupport InsertOrUpdate in beego", a.DriverName)
}
@ -537,6 +536,8 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a
updates := make([]string, len(names))
var conflitValue interface{}
for i, v := range names {
// identifier in database may not be case-sensitive, so quote it
v = fmt.Sprintf("%s%s%s", Q, v, Q)
marks[i] = "?"
valueStr := argsMap[strings.ToLower(v)]
if v == args0 {
@ -592,7 +593,7 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a
row := q.QueryRow(query, values...)
var id int64
err = row.Scan(&id)
if err.Error() == `pq: syntax error at or near "ON"` {
if err != nil && err.Error() == `pq: syntax error at or near "ON"` {
err = fmt.Errorf("postgres version must 9.5 or higher")
}
return id, err
@ -601,7 +602,7 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a
// execute update sql dbQuerier with given struct reflect.Value.
func (d *dbBase) Update(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location, cols []string) (int64, error) {
pkName, pkValue, ok := getExistPk(mi, ind)
if ok == false {
if !ok {
return 0, ErrMissPK
}
@ -620,6 +621,31 @@ func (d *dbBase) Update(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.
return 0, err
}
var findAutoNowAdd, findAutoNow bool
var index int
for i, col := range setNames {
if mi.fields.GetByColumn(col).autoNowAdd {
index = i
findAutoNowAdd = true
}
if mi.fields.GetByColumn(col).autoNow {
findAutoNow = true
}
}
if findAutoNowAdd {
setNames = append(setNames[0:index], setNames[index+1:]...)
setValues = append(setValues[0:index], setValues[index+1:]...)
}
if !findAutoNow {
for col, info := range mi.fields.columns {
if info.autoNow {
setNames = append(setNames, col)
setValues = append(setValues, time.Now())
}
}
}
setValues = append(setValues, pkValue)
Q := d.ins.TableQuote()
@ -654,7 +680,7 @@ func (d *dbBase) Delete(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.
} else {
// default use pk value as where condtion.
pkColumn, pkValue, ok := getExistPk(mi, ind)
if ok == false {
if !ok {
return 0, ErrMissPK
}
whereCols = []string{pkColumn}
@ -676,13 +702,6 @@ func (d *dbBase) Delete(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.
return 0, err
}
if num > 0 {
if mi.fields.pk.auto {
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(0)
} else {
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(0)
}
}
err := d.deleteRels(q, mi, args, tz)
if err != nil {
return num, err
@ -699,7 +718,7 @@ func (d *dbBase) UpdateBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
columns := make([]string, 0, len(params))
values := make([]interface{}, 0, len(params))
for col, val := range params {
if fi, ok := mi.fields.GetByAny(col); ok == false || fi.dbcol == false {
if fi, ok := mi.fields.GetByAny(col); !ok || !fi.dbcol {
panic(fmt.Errorf("wrong field/column name `%s`", col))
} else {
columns = append(columns, fi.column)
@ -744,6 +763,16 @@ func (d *dbBase) UpdateBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
cols = append(cols, col+" = "+col+" * ?")
case ColExcept:
cols = append(cols, col+" = "+col+" / ?")
case ColBitAnd:
cols = append(cols, col+" = "+col+" & ?")
case ColBitRShift:
cols = append(cols, col+" = "+col+" >> ?")
case ColBitLShift:
cols = append(cols, col+" = "+col+" << ?")
case ColBitXOR:
cols = append(cols, col+" = "+col+" ^ ?")
case ColBitOr:
cols = append(cols, col+" = "+col+" | ?")
}
values[i] = c.value
} else {
@ -761,7 +790,13 @@ func (d *dbBase) UpdateBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
}
d.ins.ReplaceMarks(&query)
res, err := q.Exec(query, values...)
var err error
var res sql.Result
if qs != nil && qs.forContext {
res, err = q.ExecContext(qs.ctx, query, values...)
} else {
res, err = q.Exec(query, values...)
}
if err == nil {
return res.RowsAffected()
}
@ -834,7 +869,11 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
if err := rs.Scan(&ref); err != nil {
return 0, err
}
args = append(args, reflect.ValueOf(ref).Interface())
pkValue, err := d.convertValueFromDB(mi.fields.pk, reflect.ValueOf(ref).Interface(), tz)
if err != nil {
return 0, err
}
args = append(args, pkValue)
cnt++
}
@ -846,11 +885,16 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
for i := range marks {
marks[i] = "?"
}
sql := fmt.Sprintf("IN (%s)", strings.Join(marks, ", "))
query = fmt.Sprintf("DELETE FROM %s%s%s WHERE %s%s%s %s", Q, mi.table, Q, Q, mi.fields.pk.column, Q, sql)
sqlIn := fmt.Sprintf("IN (%s)", strings.Join(marks, ", "))
query = fmt.Sprintf("DELETE FROM %s%s%s WHERE %s%s%s %s", Q, mi.table, Q, Q, mi.fields.pk.column, Q, sqlIn)
d.ins.ReplaceMarks(&query)
res, err := q.Exec(query, args...)
var res sql.Result
if qs != nil && qs.forContext {
res, err = q.ExecContext(qs.ctx, query, args...)
} else {
res, err = q.Exec(query, args...)
}
if err == nil {
num, err := res.RowsAffected()
if err != nil {
@ -923,13 +967,13 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
maps[fi.column] = true
}
} else {
panic(fmt.Errorf("wrong field/column name `%s`", col))
return 0, fmt.Errorf("wrong field/column name `%s`", col)
}
}
if hasRel {
for _, fi := range mi.fields.fieldsDB {
if fi.fieldType&IsRelField > 0 {
if maps[fi.column] == false {
if !maps[fi.column] {
tCols = append(tCols, fi.column)
}
}
@ -966,14 +1010,25 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
}
query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s%s", sqlSelect, sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit)
if qs.forupdate {
query += " FOR UPDATE"
}
d.ins.ReplaceMarks(&query)
var rs *sql.Rows
r, err := q.Query(query, args...)
if err != nil {
return 0, err
var err error
if qs != nil && qs.forContext {
rs, err = q.QueryContext(qs.ctx, query, args...)
if err != nil {
return 0, err
}
} else {
rs, err = q.Query(query, args...)
if err != nil {
return 0, err
}
}
rs = r
refs := make([]interface{}, colsNum)
for i := range refs {
@ -987,7 +1042,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
var cnt int64
for rs.Next() {
if one && cnt == 0 || one == false {
if one && cnt == 0 || !one {
if err := rs.Scan(refs...); err != nil {
return 0, err
}
@ -1067,7 +1122,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
cnt++
}
if one == false {
if !one {
if cnt > 0 {
ind.Set(slice)
} else {
@ -1102,15 +1157,19 @@ func (d *dbBase) Count(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition
d.ins.ReplaceMarks(&query)
row := q.QueryRow(query, args...)
var row *sql.Row
if qs != nil && qs.forContext {
row = q.QueryRowContext(qs.ctx, query, args...)
} else {
row = q.QueryRow(query, args...)
}
err = row.Scan(&cnt)
return
}
// generate sql with replacing operator string placeholders and replaced values.
func (d *dbBase) GenerateOperatorSQL(mi *modelInfo, fi *fieldInfo, operator string, args []interface{}, tz *time.Location) (string, []interface{}) {
sql := ""
var sql string
params := getFlatParams(fi, args, tz)
if len(params) == 0 {
@ -1237,7 +1296,7 @@ setValue:
}
value = b
}
case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJSONField || fieldType == TypeJsonbField:
case fieldType == TypeVarCharField || fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJSONField || fieldType == TypeJsonbField:
if str == nil {
value = ToStr(val)
} else {
@ -1357,7 +1416,7 @@ end:
func (d *dbBase) setFieldValue(fi *fieldInfo, value interface{}, field reflect.Value) (interface{}, error) {
fieldType := fi.fieldType
isNative := fi.isFielder == false
isNative := !fi.isFielder
setValue:
switch {
@ -1383,7 +1442,7 @@ setValue:
field.SetBool(value.(bool))
}
}
case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJSONField || fieldType == TypeJsonbField:
case fieldType == TypeVarCharField || fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJSONField || fieldType == TypeJsonbField:
if isNative {
if ns, ok := field.Interface().(sql.NullString); ok {
if value == nil {
@ -1533,7 +1592,7 @@ setValue:
}
}
if isNative == false {
if !isNative {
fd := field.Addr().Interface().(Fielder)
err := fd.SetRaw(value)
if err != nil {
@ -1594,7 +1653,7 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
infos = make([]*fieldInfo, 0, len(exprs))
for _, ex := range exprs {
index, name, fi, suc := tables.parseExprs(mi, strings.Split(ex, ExprSep))
if suc == false {
if !suc {
panic(fmt.Errorf("unknown field/column name `%s`", ex))
}
cols = append(cols, fmt.Sprintf("%s.%s%s%s %s%s%s", index, Q, fi.column, Q, Q, name, Q))
@ -1733,7 +1792,7 @@ func (d *dbBase) TableQuote() string {
return "`"
}
// replace value placeholer in parametered sql string.
// replace value placeholder in parametered sql string.
func (d *dbBase) ReplaceMarks(query *string) {
// default use `?` as mark, do nothing
}

View File

@ -15,8 +15,10 @@
package orm
import (
"context"
"database/sql"
"fmt"
lru "github.com/hashicorp/golang-lru"
"reflect"
"sync"
"time"
@ -60,6 +62,8 @@ var (
"sqlite3": DRSqlite,
"tidb": DRTiDB,
"oracle": DROracle,
"oci8": DROracle, // github.com/mattn/go-oci8
"ora": DROracle, //https://github.com/rana/ora
}
dbBasers = map[DriverType]dbBaser{
DRMySQL: newdbBaseMysql(),
@ -101,6 +105,121 @@ func (ac *_dbCache) getDefault() (al *alias) {
return
}
type DB struct {
*sync.RWMutex
DB *sql.DB
stmtDecorators *lru.Cache
}
func (d *DB) Begin() (*sql.Tx, error) {
return d.DB.Begin()
}
func (d *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) {
return d.DB.BeginTx(ctx, opts)
}
//su must call release to release *sql.Stmt after using
func (d *DB) getStmtDecorator(query string) (*stmtDecorator, error) {
d.RLock()
c, ok := d.stmtDecorators.Get(query)
if ok {
c.(*stmtDecorator).acquire()
d.RUnlock()
return c.(*stmtDecorator), nil
}
d.RUnlock()
d.Lock()
c, ok = d.stmtDecorators.Get(query)
if ok {
c.(*stmtDecorator).acquire()
d.Unlock()
return c.(*stmtDecorator), nil
}
stmt, err := d.Prepare(query)
if err != nil {
d.Unlock()
return nil, err
}
sd := newStmtDecorator(stmt)
sd.acquire()
d.stmtDecorators.Add(query, sd)
d.Unlock()
return sd, nil
}
func (d *DB) Prepare(query string) (*sql.Stmt, error) {
return d.DB.Prepare(query)
}
func (d *DB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
return d.DB.PrepareContext(ctx, query)
}
func (d *DB) Exec(query string, args ...interface{}) (sql.Result, error) {
sd, err := d.getStmtDecorator(query)
if err != nil {
return nil, err
}
stmt := sd.getStmt()
defer sd.release()
return stmt.Exec(args...)
}
func (d *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
sd, err := d.getStmtDecorator(query)
if err != nil {
return nil, err
}
stmt := sd.getStmt()
defer sd.release()
return stmt.ExecContext(ctx, args...)
}
func (d *DB) Query(query string, args ...interface{}) (*sql.Rows, error) {
sd, err := d.getStmtDecorator(query)
if err != nil {
return nil, err
}
stmt := sd.getStmt()
defer sd.release()
return stmt.Query(args...)
}
func (d *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
sd, err := d.getStmtDecorator(query)
if err != nil {
return nil, err
}
stmt := sd.getStmt()
defer sd.release()
return stmt.QueryContext(ctx, args...)
}
func (d *DB) QueryRow(query string, args ...interface{}) *sql.Row {
sd, err := d.getStmtDecorator(query)
if err != nil {
panic(err)
}
stmt := sd.getStmt()
defer sd.release()
return stmt.QueryRow(args...)
}
func (d *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
sd, err := d.getStmtDecorator(query)
if err != nil {
panic(err)
}
stmt := sd.getStmt()
defer sd.release()
return stmt.QueryRowContext(ctx, args)
}
type alias struct {
Name string
Driver DriverType
@ -108,7 +227,7 @@ type alias struct {
DataSource string
MaxIdleConns int
MaxOpenConns int
DB *sql.DB
DB *DB
DbBaser dbBaser
TZ *time.Location
Engine string
@ -117,7 +236,7 @@ type alias struct {
func detectTZ(al *alias) {
// orm timezone system match database
// default use Local
al.TZ = time.Local
al.TZ = DefaultTimeLoc
if al.DriverName == "sphinx" {
return
@ -134,7 +253,9 @@ func detectTZ(al *alias) {
}
t, err := time.Parse("-07:00:00", tz)
if err == nil {
al.TZ = t.Location()
if t.Location().String() != "" {
al.TZ = t.Location()
}
} else {
DebugLog.Printf("Detect DB timezone: %s %s\n", tz, err.Error())
}
@ -172,7 +293,11 @@ func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) {
al := new(alias)
al.Name = aliasName
al.DriverName = driverName
al.DB = db
al.DB = &DB{
RWMutex: new(sync.RWMutex),
DB: db,
stmtDecorators: newStmtDecoratorLruWithEvict(),
}
if dr, ok := drivers[driverName]; ok {
al.DbBaser = dbBasers[dr]
@ -186,7 +311,7 @@ func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) {
return nil, fmt.Errorf("register db Ping `%s`, %s", aliasName, err.Error())
}
if dataBaseCache.add(aliasName, al) == false {
if !dataBaseCache.add(aliasName, al) {
return nil, fmt.Errorf("DataBase alias name `%s` already registered, cannot reuse", aliasName)
}
@ -244,11 +369,11 @@ end:
// RegisterDriver Register a database driver use specify driver name, this can be definition the driver is which database type.
func RegisterDriver(driverName string, typ DriverType) error {
if t, ok := drivers[driverName]; ok == false {
if t, ok := drivers[driverName]; !ok {
drivers[driverName] = typ
} else {
if t != typ {
return fmt.Errorf("driverName `%s` db driver already registered and is other type\n", driverName)
return fmt.Errorf("driverName `%s` db driver already registered and is other type", driverName)
}
}
return nil
@ -259,7 +384,7 @@ func SetDataBaseTZ(aliasName string, tz *time.Location) error {
if al, ok := dataBaseCache.get(aliasName); ok {
al.TZ = tz
} else {
return fmt.Errorf("DataBase alias name `%s` not registered\n", aliasName)
return fmt.Errorf("DataBase alias name `%s` not registered", aliasName)
}
return nil
}
@ -268,13 +393,14 @@ func SetDataBaseTZ(aliasName string, tz *time.Location) error {
func SetMaxIdleConns(aliasName string, maxIdleConns int) {
al := getDbAlias(aliasName)
al.MaxIdleConns = maxIdleConns
al.DB.SetMaxIdleConns(maxIdleConns)
al.DB.DB.SetMaxIdleConns(maxIdleConns)
}
// SetMaxOpenConns Change the max open conns for *sql.DB, use specify database alias name
func SetMaxOpenConns(aliasName string, maxOpenConns int) {
al := getDbAlias(aliasName)
al.MaxOpenConns = maxOpenConns
al.DB.DB.SetMaxOpenConns(maxOpenConns)
// for tip go 1.2
if fun := reflect.ValueOf(al.DB).MethodByName("SetMaxOpenConns"); fun.IsValid() {
fun.Call([]reflect.Value{reflect.ValueOf(maxOpenConns)})
@ -292,7 +418,48 @@ func GetDB(aliasNames ...string) (*sql.DB, error) {
}
al, ok := dataBaseCache.get(name)
if ok {
return al.DB, nil
return al.DB.DB, nil
}
return nil, fmt.Errorf("DataBase of alias name `%s` not found\n", name)
return nil, fmt.Errorf("DataBase of alias name `%s` not found", name)
}
type stmtDecorator struct {
wg sync.WaitGroup
lastUse int64
stmt *sql.Stmt
}
func (s *stmtDecorator) getStmt() *sql.Stmt {
return s.stmt
}
func (s *stmtDecorator) acquire() {
s.wg.Add(1)
s.lastUse = time.Now().Unix()
}
func (s *stmtDecorator) release() {
s.wg.Done()
}
//garbage recycle for stmt
func (s *stmtDecorator) destroy() {
go func() {
s.wg.Wait()
_ = s.stmt.Close()
}()
}
func newStmtDecorator(sqlStmt *sql.Stmt) *stmtDecorator {
return &stmtDecorator{
stmt: sqlStmt,
lastUse: time.Now().Unix(),
}
}
func newStmtDecoratorLruWithEvict() *lru.Cache {
cache, _ := lru.NewWithEvict(1000, func(key interface{}, value interface{}) {
value.(*stmtDecorator).destroy()
})
return cache
}

View File

@ -46,6 +46,7 @@ var mysqlTypes = map[string]string{
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "varchar(%d)",
"string-char": "char(%d)",
"string-text": "longtext",
"time.Time-date": "date",
"time.Time": "datetime",
@ -103,8 +104,7 @@ func (d *dbBaseMysql) IndexExists(db dbQuerier, table string, name string) bool
// If no will insert
// Add "`" for mysql sql building
func (d *dbBaseMysql) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a *alias, args ...string) (int64, error) {
iouStr := ""
var iouStr string
argsMap := map[string]string{}
iouStr = "ON DUPLICATE KEY UPDATE"

View File

@ -34,6 +34,7 @@ var oracleTypes = map[string]string{
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "VARCHAR2(%d)",
"string-char": "CHAR(%d)",
"string-text": "VARCHAR2(%d)",
"time.Time-date": "DATE",
"time.Time": "TIMESTAMP",
@ -94,3 +95,43 @@ func (d *dbBaseOracle) IndexExists(db dbQuerier, table string, name string) bool
row.Scan(&cnt)
return cnt > 0
}
// execute insert sql with given struct and given values.
// insert the given values, not the field values in struct.
func (d *dbBaseOracle) InsertValue(q dbQuerier, mi *modelInfo, isMulti bool, names []string, values []interface{}) (int64, error) {
Q := d.ins.TableQuote()
marks := make([]string, len(names))
for i := range marks {
marks[i] = ":" + names[i]
}
sep := fmt.Sprintf("%s, %s", Q, Q)
qmarks := strings.Join(marks, ", ")
columns := strings.Join(names, sep)
multi := len(values) / len(names)
if isMulti {
qmarks = strings.Repeat(qmarks+"), (", multi-1) + qmarks
}
query := fmt.Sprintf("INSERT INTO %s%s%s (%s%s%s) VALUES (%s)", Q, mi.table, Q, Q, columns, Q, qmarks)
d.ins.ReplaceMarks(&query)
if isMulti || !d.ins.HasReturningID(mi, &query) {
res, err := q.Exec(query, values...)
if err == nil {
if isMulti {
return res.RowsAffected()
}
return res.LastInsertId()
}
return 0, err
}
row := q.QueryRow(query, values...)
var id int64
err := row.Scan(&id)
return id, err
}

View File

@ -43,6 +43,7 @@ var postgresTypes = map[string]string{
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "varchar(%d)",
"string-char": "char(%d)",
"string-text": "text",
"time.Time-date": "date",
"time.Time": "timestamp with time zone",

View File

@ -17,6 +17,8 @@ package orm
import (
"database/sql"
"fmt"
"reflect"
"time"
)
// sqlite operators.
@ -43,6 +45,7 @@ var sqliteTypes = map[string]string{
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "varchar(%d)",
"string-char": "character(%d)",
"string-text": "text",
"time.Time-date": "date",
"time.Time": "datetime",
@ -65,6 +68,14 @@ type dbBaseSqlite struct {
var _ dbBaser = new(dbBaseSqlite)
// override base db read for update behavior as SQlite does not support syntax
func (d *dbBaseSqlite) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location, cols []string, isForUpdate bool) error {
if isForUpdate {
DebugLog.Println("[WARN] SQLite does not support SELECT FOR UPDATE query, isForUpdate param is ignored and always as false to do the work")
}
return d.dbBase.Read(q, mi, ind, tz, cols, false)
}
// get sqlite operator.
func (d *dbBaseSqlite) OperatorSQL(operator string) string {
return sqliteOperators[operator]
@ -134,7 +145,7 @@ func (d *dbBaseSqlite) IndexExists(db dbQuerier, table string, name string) bool
defer rows.Close()
for rows.Next() {
var tmp, index sql.NullString
rows.Scan(&tmp, &index, &tmp)
rows.Scan(&tmp, &index, &tmp, &tmp, &tmp)
if name == index.String {
return true
}

View File

@ -63,7 +63,7 @@ func (t *dbTables) set(names []string, mi *modelInfo, fi *fieldInfo, inner bool)
// add table info to collection.
func (t *dbTables) add(names []string, mi *modelInfo, fi *fieldInfo, inner bool) (*dbTable, bool) {
name := strings.Join(names, ExprSep)
if _, ok := t.tablesM[name]; ok == false {
if _, ok := t.tablesM[name]; !ok {
i := len(t.tables) + 1
jt := &dbTable{i, fmt.Sprintf("T%d", i), name, names, false, inner, mi, fi, nil}
t.tablesM[name] = jt
@ -261,7 +261,7 @@ loopFor:
fiN, okN = mmi.fields.GetByAny(exprs[i+1])
}
if isRel && (fi.mi.isThrough == false || num != i) {
if isRel && (!fi.mi.isThrough || num != i) {
if fi.null || t.skipEnd {
inner = false
}
@ -364,7 +364,7 @@ func (t *dbTables) getCondSQL(cond *Condition, sub bool, tz *time.Location) (whe
}
index, _, fi, suc := t.parseExprs(mi, exprs)
if suc == false {
if !suc {
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(p.exprs, ExprSep)))
}
@ -372,7 +372,13 @@ func (t *dbTables) getCondSQL(cond *Condition, sub bool, tz *time.Location) (whe
operator = "exact"
}
operSQL, args := t.base.GenerateOperatorSQL(mi, fi, operator, p.args, tz)
var operSQL string
var args []interface{}
if p.isRaw {
operSQL = p.sql
} else {
operSQL, args = t.base.GenerateOperatorSQL(mi, fi, operator, p.args, tz)
}
leftCol := fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q)
t.base.GenerateOperatorLeftCol(fi, operator, &leftCol)
@ -383,7 +389,7 @@ func (t *dbTables) getCondSQL(cond *Condition, sub bool, tz *time.Location) (whe
}
}
if sub == false && where != "" {
if !sub && where != "" {
where = "WHERE " + where
}
@ -403,7 +409,7 @@ func (t *dbTables) getGroupSQL(groups []string) (groupSQL string) {
exprs := strings.Split(group, ExprSep)
index, _, fi, suc := t.parseExprs(t.mi, exprs)
if suc == false {
if !suc {
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
}
@ -432,7 +438,7 @@ func (t *dbTables) getOrderSQL(orders []string) (orderSQL string) {
exprs := strings.Split(order, ExprSep)
index, _, fi, suc := t.parseExprs(t.mi, exprs)
if suc == false {
if !suc {
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
}

Some files were not shown because too many files have changed in this diff Show More