Skip to content

Commit

Permalink
添加日志报告 (#331)
Browse files Browse the repository at this point in the history
添加日志报告
  • Loading branch information
winddies authored and nighca committed Feb 24, 2018
1 parent 2280689 commit 28cb1a2
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 30 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,20 @@ subscription.unsubscribe() // 上传取消
}
}
```
* next: 接收上传进度信息,res 参数是一个带有 `total` 字段的 `object`,包含`loaded``total``percent`三个属性,提供上传进度信息。
* next: 接收上传进度信息,res是一个带有 `total` 字段的 `object`,包含`loaded``total``percent`三个属性,提供上传进度信息。
* total.loaded: `number`,已上传大小,单位为字节。
* total.total: `number`,本次上传的总量控制信息,单位为字节,注意这里的 total 跟文件大小并不一致。
* total.percent: `number`,当前上传进度,范围:0100

* error: 上传错误后触发,当不是 xhr 请求错误时,会把当前错误产生原因直接抛出,诸如 JSON 解析异常等;当产生 xhr 请求错误时,参数 err 为一个包含 `code``message``isRequestError` 三个属性的 `object`
* err.isRequestError: 用于区分是否 xhr 请求错误;当 xhr 请求出现错误并且后端通过 HTTP 状态码返回了错误信息时,该参数为 `true`;否则为 `undefined`
* err.reqId: `string`,xhr请求错误的 `X-Reqid`
* err.code: `number`,请求错误状态码,只有在 `err.isRequestError`true 的时候才有效,可查阅码值对应[说明](https://developer.qiniu.com/kodo/api/3928/error-responses)。
* err.message: `string`,错误信息,包含错误码,当后端返回提示信息时也会有相应的错误信息。

* complete: 接收上传完成后的后端返回信息,res 参数为一个 `object`, 为上传成功后后端返回的信息,具体返回结构取决于后端sdk的配置,可参考[上传策略](https://developer.qiniu.com/kodo/manual/1206/put-policy)。
* complete: 接收上传完成后的后端返回信息,具体返回结构取决于后端sdk的配置,可参考[上传策略](https://developer.qiniu.com/kodo/manual/1206/put-policy)。

* subscription: 为一个带有 `unsubscribe` 方法的类实例,通过调用 `subscription.unsubscribe()` 停止当前文件上传
* subscription: 为一个带有 `unsubscribe` 方法的类实例,通过调用 `subscription.unsubscribe()` 停止当前文件上传

* **file**: `Blob` 对象,上传的文件
* **key**: 文件资源名
Expand All @@ -159,8 +160,9 @@ subscription.unsubscribe() // 上传取消
};
```

* config.useCdnDomain: 表示是否使用 cdn 加速域名,为布尔值,`true` 表示使用,默认为 `false`
* config.region: 选择上传域名区域,默认为(z0)华东
* config.useCdnDomain: 表示是否使用 cdn 加速域名,为布尔值,`true` 表示使用,默认为 `false`
* config.disableStatisticsReport: 是否禁用日志报告,为布尔值,默认为 `false`
* config.region: 选择上传域名区域,默认为(z0)华东。

* **putExtra**:

Expand Down
6 changes: 5 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import {
import { UploadManager } from "./upload";
import { imageMogr2, watermark, imageInfo, exif, pipeline } from "./image";
import { Observable } from "./observable";
import { StatisticsLogger } from './statisticsLog'

let statisticsLogger = new StatisticsLogger();

function upload(file, key, token, putExtra, config) {

let options = {
file,
key,
Expand All @@ -24,7 +28,7 @@ function upload(file, key, token, putExtra, config) {
onData: e => observer.next(e),
onError: e => observer.error(e),
onComplete: e => observer.complete(e)
});
}, statisticsLogger);
uploadManager.putFile();
return uploadManager.stop.bind(uploadManager);
});
Expand Down
28 changes: 28 additions & 0 deletions src/statisticsLog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {createXHR} from './utils'

export class StatisticsLogger{

log(info, token) {
let logString = "";
Object.keys(info).forEach(k => logString += info[k] + ",");
this.send(logString, token);
}

send(logString, token){
let xhr = createXHR();
let count = 0;
xhr.open('POST', "https://uplog.qbox.me/log/3");
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('Authorization', 'UpToken ' + token);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status !== 200) {
count++;
count <=3 ? xhr.send(logString) : "";
}
}
};
xhr.send(logString);
}

}
70 changes: 49 additions & 21 deletions src/upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
removeLocalFileInfo,
isContainFileMimeType,
sum,
getDomainFromUrl,
getPortFromUrl,
getHeadersForChunkUpload,
getHeadersForMkFile,
request,
Expand All @@ -19,10 +21,11 @@ import {
let BLOCK_SIZE = 4 * 1024 * 1024;

export class UploadManager {
constructor(options, handlers) {
constructor(options, handlers, statisticsLogger) {
this.config = Object.assign(
{
useCdnDomain: true,
disableStatisticsReport: false,
region: null
},
options.config
Expand All @@ -35,6 +38,8 @@ export class UploadManager {
},
options.putExtra
);
this.statisticsLogger = statisticsLogger;
this.progress = null;
this.xhrList = [];
this.xhrHandler = xhr => this.xhrList.push(xhr);
this.file = options.file;
Expand All @@ -60,14 +65,25 @@ export class UploadManager {
}

this.uploadUrl = getUploadUrl(this.config);
this.uploadAt = new Date().getTime();

let upload =
this.file.size > BLOCK_SIZE ? this.resumeUpload() : this.directUpload();
upload.then(res => this.onComplete(res), err => {
let upload = this.file.size > BLOCK_SIZE ? this.resumeUpload() : this.directUpload();
upload.then(res => {
this.onComplete(res.data);
if(!this.config.disableStatisticsReport){
this.sendLog(res.reqId, 200);
}
}, err => {
this.onError(err);
if(err.isRequestError && !this.config.disableStatisticsReport){
if(err.code !== 0){
this.sendLog(err.reqId, err.code);
}else{
this.sendLog("", -2);
}
}
this.stop();
})

return upload;
}

Expand All @@ -76,6 +92,21 @@ export class UploadManager {
this.xhrList = [];
}

sendLog(reqId, code){
this.statisticsLogger.log({
code: code,
reqId: reqId,
host: getDomainFromUrl(this.uploadUrl),
remoteIp: "",
port: getPortFromUrl(this.uploadUrl),
duration: (new Date().getTime() - this.uploadAt)/1000,
time: Math.floor(this.uploadAt/1000),
bytesSent: this.progress ? this.progress.total.loaded : 0,
upType: "jssdk-h5",
size: this.file.size
}, this.token)
}

// 直传
directUpload() {
let formData = new FormData();
Expand Down Expand Up @@ -185,8 +216,7 @@ export class UploadManager {
let headers = getHeadersForMkFile(this.token);
let onCreate = this.xhrHandler;
let method = "POST";

return request(requestUrL, { method, body, headers, onCreate }).then(
return request(requestUrL, { method, body, headers, onCreate}).then(
res => {
this.updateMkFileProgress(1);
return Promise.resolve(res);
Expand All @@ -195,9 +225,8 @@ export class UploadManager {
}

updateDirectProgress(loaded, total) {
this.onData(
{total: this.getProgressInfoItem(loaded, total)}
)
this.progress = {total: this.getProgressInfoItem(loaded, total)}
this.onData(this.progress)
}

initChunksProgress() {
Expand All @@ -216,17 +245,16 @@ export class UploadManager {
}

notifyResumeProgress() {
this.onData(
{
total: this.getProgressInfoItem(
sum(this.loaded.chunks) + this.loaded.mkFileProgress,
this.file.size + 1
),
chunks: this.chunks.map((chunk, index) => {
return this.getProgressInfoItem(this.loaded.chunks[index], chunk.size);
})
}
);
this.progress = {
total: this.getProgressInfoItem(
sum(this.loaded.chunks) + this.loaded.mkFileProgress,
this.file.size + 1
),
chunks: this.chunks.map((chunk, index) => {
return this.getProgressInfoItem(this.loaded.chunks[index], chunk.size);
})
};
this.onData(this.progress);
}

getProgressInfoItem(loaded, size) {
Expand Down
32 changes: 30 additions & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,16 +170,17 @@ export function request(url, options) {
if (xhr.readyState !== 4) {
return;
}
let reqId = xhr.getResponseHeader("x-reqId")|| "";
if (xhr.status !== 200) {
let message = `xhr request failed, code: ${xhr.status};`;
if (responseText) {
message = message + ` response: ${responseText}`;
}
reject({code: xhr.status, message: message, isRequestError: true});
reject({code: xhr.status, message: message,reqId: reqId, isRequestError: true});
return;
}
try {
resolve(JSON.parse(responseText))
resolve({data: JSON.parse(responseText), reqId: reqId})
} catch (err) {
reject(err)
}
Expand All @@ -189,6 +190,33 @@ export function request(url, options) {
});
}

export function getPortFromUrl(url) {
if (url && url.match) {
let groups = url.match(/(^https?)/);
if (!groups) {
return "";
}
let type = groups[1];
groups = url.match(/^https?:\/\/([^:^/]*):(\d*)/);
if (groups) {
return groups[2];
}
if (type === "http") {
return "80";
}
return "443";
}
return "";
}

export function getDomainFromUrl (url) {
if (url && url.match) {
let groups = url.match(/^https?:\/\/([^:^/]*)/);
return groups ? groups[1] : "";
}
return "";
}

// 构造区域上传url
export function getUploadUrl(config) {
let upHosts = regionUphostMap[config.region] || regionUphostMap[region.z0];
Expand Down
2 changes: 1 addition & 1 deletion test/config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'AccessKey': '<Your Access Key>', // https://portal.qiniu.com/user/key
'SecretKey': '<Your Secret Key>',
'Bucket': '<Your Bucket Name>',
'Port': 19110,
'Port': 9000,
'UptokenUrl': 'uptoken',
'Domain': '<Your Bucket Domain>' // bucket domain eg:http://qiniu-plupload.qiniudn.com/
};
1 change: 1 addition & 0 deletions test/demo1/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var domain = res.domain;
var config = {
useCdnDomain: true,
disableStatisticsReport: false,
region: qiniu.region.z2
};
var putExtra = {
Expand Down

0 comments on commit 28cb1a2

Please sign in to comment.