Commit bea6f4c1 authored by jiangrujie's avatar jiangrujie

Add documentation in english

parent f3b388a8
......@@ -83,7 +83,7 @@ URL的一般形式如下图:
确实,在简单使用场景下,这两者有所重复,但在复杂场景中,两者差别很大,比如:
- 访问挂在bns下的多个http server。此时Channel.Init传入的是bns节点名称,对uri()的赋值则是包含Host的完整URL(比如"www.foo.com/index.html?name=value"),BNS下所有的http server都会看到"Host: www.foo.com";uri()也可以是只包含路径的URL,比如"/index.html?name=value",框架会以目标server的ip和port为Host,地址为10.46.188.39:8989的http server将会看到"Host: 10.46.188.39:8989"。
- 访问挂在bns下的多个http server。此时Channel.Init传入的是bns节点名称,对uri()的赋值则是包含Host的完整URL(比如"www.foo.com/index.html?name=value"),BNS下所有的http server都会看到"Host: [www.foo.com](http://www.foo.com/)";uri()也可以是只包含路径的URL,比如"/index.html?name=value",框架会以目标server的ip和port为Host,地址为10.46.188.39:8989的http server将会看到"Host: 10.46.188.39:8989"。
- 通过http proxy访问目标server。此时Channel.Init传入的是proxy server的地址,但uri()填入的是目标server的URL。
# 常见设置
......@@ -132,7 +132,7 @@ os.move_to(cntl->request_attachment());
Notes on http header:
- 根据 HTTP 协议[规定](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), header 的 field_name部分不区分大小写。在r33861前,field_name都转为了小写,在r33861后,大小写能保持不变(仍然支持大小写不敏感)
- 根据 HTTP 协议[规定](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), header 的 field_name部分不区分大小写。brpc对于field_name大小写保持不变,且仍然支持大小写不敏感
- 如果 HTTP 头中出现了相同的 field_name, 根据协议[规定](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),value将被合并到一起, 中间用逗号(,) 分隔, 具体value如何理解,需要用户自己确定.
- query之间用"&"分隔, key和value之间用"="分隔, value可以省略,比如key1=value1&key2&key3=value3中key2是合理的query,值为空字符串。
......@@ -144,12 +144,11 @@ Notes on http header:
当Server返回的http status code不是2xx时,该次http访问即视为失败,client端会设置对应的ErrorCode:
- 在r31923前,1xx和3xx错误对应EPROTONOSUPPORT,4xx错误对应EREQUEST,其余错误对应EINTERNAL。http body不会置入`cntl->response_attachment()`
- 在r31923后,所有错误被统一为EHTTP。如果用户发现`cntl->ErrorCode()`为EHTTP,那么可以检查`cntl->http_response().status_code()`以获得具体的http错误。同时http body会置入`cntl->response_attachment()`,用户可以把代表错误的html或json传递回来。
- 所有错误被统一为EHTTP。如果用户发现`cntl->ErrorCode()`为EHTTP,那么可以检查`cntl->http_response().status_code()`以获得具体的http错误。同时http body会置入`cntl->response_attachment()`,用户可以把代表错误的html或json传递回来。
# 压缩request body
在r33877后,调用Controller::set_request_compress_type(brpc::COMPRESS_TYPE_GZIP)可将http body用gzip压缩,并设置"Content-Encoding"为"gzip"。
调用Controller::set_request_compress_type(brpc::COMPRESS_TYPE_GZIP)可将http body用gzip压缩,并设置"Content-Encoding"为"gzip"。
# 解压response body
......@@ -172,9 +171,9 @@ if (encoding != NULL && *encoding == "gzip") {
# 持续下载
r33796前brpc client在下载一个超长的body时,需要一直等待直到body完整才会视作RPC结束,这个过程中超长body都会存在内存中,如果body是无限长的(比如直播用的flv文件),那么内存会持续增长,直到超时。换句话说,r33796前的brpc client不适合下载大文件。
通常下载一个超长的body时,需要一直等待直到body完整才会视作RPC结束,这个过程中超长body都会存在内存中,如果body是无限长的(比如直播用的flv文件),那么内存会持续增长,直到超时。这样的http client不适合下载大文件。
r33796后brpc client支持在读取完body前就结束RPC,让用户在RPC结束后再读取持续增长的body。注意这个功能不等同于“支持http chunked mode”,brpc的http实现一直支持解析chunked mode,这里的问题是如何让用户处理超长或无限长的body,和body是否以chunked mode传输无关。
brpc client支持在读取完body前就结束RPC,让用户在RPC结束后再读取持续增长的body。注意这个功能不等同于“支持http chunked mode”,brpc的http实现一直支持解析chunked mode,这里的问题是如何让用户处理超长或无限长的body,和body是否以chunked mode传输无关。
使用方法如下:
......@@ -215,4 +214,4 @@ r33796后brpc client支持在读取完body前就结束RPC,让用户在RPC结
# 访问带认证的Server
根据Server的认证方式生成对应的auth_data,并设置为http header "Authorization"的值。比如用的是curl,那就加上选项`-H "Authorization : <auth_data>"。`查询[giano文档](http://doc.noah.baidu.com/new/baas/base_tool.md)了解如何在Shell中生成auth_data。
根据Server的认证方式生成对应的auth_data,并设置为http header "Authorization"的值。比如用的是curl,那就加上选项`-H "Authorization : <auth_data>"。`
......@@ -16,52 +16,12 @@ PLOG(FATAL) << "Fail to call function setting errno";
VLOG(1) << "verbose log tier 1";
CHECK_GT(1, 2) << "1 can't be greater than 2";
// public/common >= r32401支持限制打印频率。
LOG_EVERY_SECOND(INFO) << "High-frequent logs";
LOG_EVERY_N(ERROR, 10) << "High-frequent logs";
LOG_FIRST_N(INFO, 20) << "Logs that prints for at most 20 times";
LOG_ONCE(WARNING) << "Logs that only prints once";
```
## 配置comlog
```c++
// logging默认重定向至comlog,要配置comlog的话,要额外include comlog_sink.h
#include <butil/comlog_sink.h>
// 从./conf/log.conf读取comlog的配置。SetupFromConfig是我们提供的封装函数,不用像com_loadlog那样区分path和file。
if (logging::ComlogSink::GetInstance()->SetupFromConfig("conf/log.conf") != 0) {
LOG(ERROR) << "Fail to setup comlog from conf/log.conf";
return -1;
}
OR
// 直接调用com_loadlog从./conf/log.conf读取comlog的配置。
if (com_loadlog("./conf", "log.conf") != 0) {
LOG(ERROR) << "Fail to com_loadlog";
return -1;
}
OR
// 把日志打入./my_log/<process-name>.log中,comlog选项取默认值。
logging::ComlogSinkOptions options;
options.log_dir = "my_log";
if (logging::ComlogSink::GetInstance()->Setup(&options) != 0) {
LOG(ERROR) << "Fail to setup comlog from options";
return -1;
}
OR
// 把日志打入./log/<process-name>.log中,comlog选项取默认值。
if (logging::ComlogSink::GetInstance()->Setup(NULL) != 0) {
LOG(ERROR) << "Fail to setup comlog by default options";
return -1;
}
```
# DESCRIPTION
流式日志是打印复杂对象或模板对象的不二之选。大部分业务对象都很复杂,如果用printf形式的函数打印,你需要先把对象转成string,才能以%s输出。但string组合起来既不方便(比如没法append数字),还得分配大量的临时内存(string导致的)。C++中解决这个问题的方法便是“把日志流式地送入std::ostream对象”。比如为了打印对象A,那么我们得实现如下的函数:
......@@ -122,17 +82,17 @@ LOG(WARNING) << "Unusual thing happened ..." << ...;
LOG(TRACE) << "Something just took place..." << ...;
```
streaming log的日志等级是comlog和glog的合集,具体的来说,下表是日志等级的映射关系
streaming log的日志等级与glog映射关系如下
| streaming log | comlog | glog | 使用场景 |
| ------------- | ---------------------------- | -------------------- | ---------------------------------------- |
| FATAL | COMLOG_FATAL | FATAL (coredump) | 致命错误。但由于百度内大部分FATAL实际上非致命,所以streaming log的FATAL默认不像glog那样直接coredump,除非打开了[-crash_on_fatal_log](http://brpc.baidu.com:8765/flags/crash_on_fatal_log) |
| ERROR | COMLOG_FATAL | ERROR | 不致命的错误。 |
| WARNING | COMLOG_WARNING | WARNING | 不常见的分支。 |
| NOTICE | COMLOG_NOTICE | - | 一般来说你不应该使用NOTICE,它用于打印重要的业务日志,若要使用务必和检索端同学确认。glog没有NOTICE。 |
| INFO, TRACE | COMLOG_TRACE | INFO | 打印重要的副作用。比如打开关闭了某某资源之类的。 |
| VLOG(n) | COMLOG_TRACE | INFO | 打印分层的详细日志。 |
| DEBUG | COMLOG_TRACEVLOG(1) (NDEBUG) | INFOVLOG(1) (NDEBUG) | 仅为代码兼容性,基本没有用。若要使日志仅在未定义NDEBUG时才打印,用DLOG/DPLOG/DVLOG等即可。 |
| streaming log | glog | 使用场景 |
| ------------- | -------------------- | ---------------------------------------- |
| FATAL | FATAL (coredump) | 致命错误。但由于百度内大部分FATAL实际上非致命,所以streaming log的FATAL默认不像glog那样直接coredump,除非打开了[-crash_on_fatal_log](http://brpc.baidu.com:8765/flags/crash_on_fatal_log) |
| ERROR | ERROR | 不致命的错误。 |
| WARNING | WARNING | 不常见的分支。 |
| NOTICE | - | 一般来说你不应该使用NOTICE,它用于打印重要的业务日志,若要使用务必和检索端同学确认。glog没有NOTICE。 |
| INFO, TRACE | INFO | 打印重要的副作用。比如打开关闭了某某资源之类的。 |
| VLOG(n) | INFO | 打印分层的详细日志。 |
| DEBUG | INFOVLOG(1) (NDEBUG) | 仅为代码兼容性,基本没有用。若要使日志仅在未定义NDEBUG时才打印,用DLOG/DPLOG/DVLOG等即可。 |
## PLOG
......@@ -148,7 +108,7 @@ if (fd < 0) {
## noflush
如果你暂时不希望刷入comlog,加上noflush。这一般会用在打印循环中:
如果你暂时不希望刷到屏幕,加上noflush。这一般会用在打印循环中:
```c++
LOG(TRACE) << "Items:" << noflush;
......@@ -158,7 +118,7 @@ for (iterator it = items.begin(); it != items.end(); ++it) {
LOG(TRACE);
```
前两次TRACE日志都没有刷到comlog,而是还记录在thread-local缓冲中,第三次TRACE日志则把缓冲都刷入了comlog。如果items里面有三个元素,不加noflush的打印结果可能是这样的:
前两次TRACE日志都没有刷到屏幕,而是还记录在thread-local缓冲中,第三次TRACE日志则把缓冲都刷入了屏幕。如果items里面有三个元素,不加noflush的打印结果可能是这样的:
```
TRACE: ... Items:
......@@ -173,7 +133,7 @@ TRACE: ... item3
TRACE: ... Items: item1 item2 item3
```
r34694前noflush和调用处的pthread绑定,如果在noflush后发送了RPC(可能跨越pthread),那么日志输出可能不符合预期。r34694后noflush支持bthread,可以实现类似于UB的pushnotice的效果,即检索线程一路打印都暂不刷出(加上noflush),直到最后检索结束时再一次性刷出。注意,如果检索过程是异步的,就不应该使用noflush,因为异步显然会跨越bthread,使noflush仍然失效。
noflush支持bthread,可以实现类似于UB的pushnotice的效果,即检索线程一路打印都暂不刷出(加上noflush),直到最后检索结束时再一次性刷出。注意,如果检索过程是异步的,就不应该使用noflush,因为异步显然会跨越bthread,使noflush仍然失效。
## LOG_IF
......@@ -299,7 +259,7 @@ CHECK(x > y); // Check failed: x > y.
## LogSink
streaming log通过logging::SetLogSink修改日志刷入的目标,默认是屏幕。用户可以继承LogSink,实现自己的日志打印逻辑。我们默认提供了个LogSink实现:
streaming log通过logging::SetLogSink修改日志刷入的目标,默认是屏幕。用户可以继承LogSink,实现自己的日志打印逻辑。我们默认提供了个LogSink实现:
### StringSink
......@@ -316,9 +276,3 @@ TEST_F(StreamingLogTest, log_at) {
::logging::SetLogSink(old_sink);
}
```
### ComlogSink
定义在butil/comlog_sink.h中,把日志打印入comlog,主要用于线上系统,用法见[SYNOPSIS](#SYNOPSIS)一段。
使用ComlogSink的streaming log可以和com_writelog, ul_writelog混用。你并不需要把程序中所有日志都换成streaming log。
This diff is collapsed.
brpc uses [butil::IOBuf](https://github.com/brpc/brpc/blob/master/src/butil/iobuf.h) as data structure for attachment storage and HTTP body. It is a non-contiguous zero copy buffer, which has been proved in other projects as excellent performance. The interface of `IOBuf` is similar to `std::string`, but not the same.
If you used the `BufHandle` in Kylin before, you should notice the difference in convenience of `IOBuf`: the former hardly had any encapsulation, leaving the internal structure directly in front of the user. The user must carefully handle the reference count, which is very error prone, leading to lots of bugs.
# What IOBuf can:
- Default constructor doesn't involve copying.
- Explicit copy doesn't change source IOBuf. Only copy the management structure of IOBuf instead of the data.
- Append another IOBuf without copy.
- Append string involves copy.
- Read from/Write into fd.
- Convert to protobuf and vice versa.
- IOBufBuilder可以把IOBuf当std::ostream用。
# What IOBuf can't:
- Used as general storage structure. IOBuf should not keep a long life cycle to prevent multiple memory blocks (8K each) being locked by one IOBuf object.
# Slice
Slice 16 bytes from IOBuf:
```c++
source_buf.cut(&heading_iobuf, 16); // cut all bytes of source_buf when its length < 16
```
Remove 16 bytes:
```c++
source_buf.pop_front(16); // Empty source_buf when its length < 16
```
# Concatenate
Append to another IOBuf:
```c++
buf.append(another_buf); // no data copy
```
Append std::string
```c++
buf.append(str); // copy data of str into buf
```
# Parse
Parse protobuf from IOBuf
```c++
IOBufAsZeroCopyInputStream wrapper(&iobuf);
pb_message.ParseFromZeroCopyStream(&wrapper);
```
Parse IOBuf as user-defined structure
```c++
IOBufAsZeroCopyInputStream wrapper(&iobuf);
CodedInputStream coded_stream(&wrapper);
coded_stream.ReadLittleEndian32(&value);
...
```
# Serialize
Serialize protobuf into IOBuf
```c++
IOBufAsZeroCopyOutputStream wrapper(&iobuf);
pb_message.SerializeToZeroCopyStream(&wrapper);
```
Append printable data into IOBuf
```c++
IOBufBuilder os;
os << "anything can be sent to std::ostream";
os.buf(); // IOBuf
```
# Print
```c++
std::cout << iobuf;
std::string str = iobuf.to_string();
```
# Performance
IOBuf has excellent performance in general aspects:
| Action | Throughput | QPS |
| ---------------------------------------- | ----------- | ------- |
| Read from file -> Slice 12+16 bytes -> Copy -> Merge into another buffer ->Write to /dev/null | 240.423MB/s | 8586535 |
| Read from file -> Slice 12+128 bytes -> Copy-> Merge into another buffer ->Write to /dev/null | 790.022MB/s | 5643014 |
| Read from file -> Slice 12+1024 bytes -> Copy-> Merge into another buffer ->Write to /dev/null | 1519.99MB/s | 1467171 |
\ No newline at end of file
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment