Add HttpPipelineLogger and RequestPolicyOptions

This commit is contained in:
Dan Schulte 2018-05-04 15:03:37 -07:00
Родитель c0022b7f2e
Коммит a1f16cb580
13 изменённых файлов: 180 добавлений и 45 удалений

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
/**
* The different levels of logs that can be used with the HttpPipelineLogger.
*/
export enum HttpPipelineLogLevel {
/**
* A log level that indicates that no logs will be logged.
*/
OFF,
/**
* An error log.
*/
ERROR,
/**
* A warning log.
*/
WARNING,
/**
* An information log.
*/
INFO
}

48
lib/httpPipelineLogger.ts Normal file
Просмотреть файл

@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { HttpPipelineLogLevel } from "./httpPipelineLogLevel";
/**
* A Logger that can be added to a HttpPipeline. This enables each RequestPolicy to log messages
* that can be used for debugging purposes.
*/
export interface HttpPipelineLogger {
/**
* The log level threshold for what logs will be logged.
* @return The log level threshold for what logs will be logged.
*/
minimumLogLevel: HttpPipelineLogLevel;
/**
* Log the provided message.
* @param logLevel The HttpLogDetailLevel associated with this message.
* @param message The message to log.
* @param formattedArguments A variadic list of arguments that should be formatted into the
* provided message.
*/
log(logLevel: HttpPipelineLogLevel, message: string): void;
}
/**
* A HttpPipelineLogger that will send its logs to the console.
*/
export class ConsoleHttpPipelineLogger implements HttpPipelineLogger {
/**
* Create a new ConsoleHttpPipelineLogger.
* @param minimumLogLevel The log level threshold for what logs will be logged.
*/
constructor(public minimumLogLevel: HttpPipelineLogLevel) {
}
/**
* Log the provided message.
* @param logLevel The HttpLogDetailLevel associated with this message.
* @param message The message to log.
* @param formattedArguments A variadic list of arguments that should be formatted into the
* provided message.
*/
log(logLevel: HttpPipelineLogLevel, message: string): void {
console.log(`${HttpPipelineLogLevel[logLevel]}: ${message}`);
}
}

Просмотреть файл

@ -4,7 +4,7 @@
import { HttpOperationResponse } from "../httpOperationResponse";
import * as utils from "../util/utils";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy, RequestPolicyOptions } from "./requestPolicy";
export interface RetryData {
retryCount: number;
@ -19,8 +19,8 @@ export interface RetryError extends Error {
}
export function exponentialRetryPolicy(retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new ExponentialRetryPolicy(nextPolicy, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new ExponentialRetryPolicy(nextPolicy, options, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
};
}
@ -45,8 +45,8 @@ export class ExponentialRetryPolicy extends BaseRequestPolicy {
DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90;
DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3;
constructor(nextPolicy: RequestPolicy, retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number) {
super(nextPolicy, options);
this.retryCount = typeof retryCount === "number" ? retryCount : this.DEFAULT_CLIENT_RETRY_COUNT;
this.retryInterval = typeof retryInterval === "number" ? retryInterval : this.DEFAULT_CLIENT_RETRY_INTERVAL;
this.minRetryInterval = typeof minRetryInterval === "number" ? minRetryInterval : this.DEFAULT_CLIENT_MIN_RETRY_INTERVAL;

Просмотреть файл

@ -3,11 +3,11 @@
import { HttpOperationResponse } from "../httpOperationResponse";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy, RequestPolicyOptions } from "./requestPolicy";
export function logPolicy(logger: any = console.log): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new LogPolicy(nextPolicy, logger);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new LogPolicy(nextPolicy, options, logger);
};
}
@ -15,8 +15,8 @@ export class LogPolicy extends BaseRequestPolicy {
logger?: any;
constructor(nextPolicy: RequestPolicy, logger: any = console.log) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, logger: any = console.log) {
super(nextPolicy, options);
this.logger = logger;
}

Просмотреть файл

@ -6,13 +6,13 @@ import { HttpOperationResponse } from "../httpOperationResponse";
import { Constants } from "../util/constants";
import { isNode } from "../util/utils";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy, RequestPolicyOptions } from "./requestPolicy";
const HeaderConstants = Constants.HeaderConstants;
export function msRestUserAgentPolicy(userAgentInfo: Array<string>): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new MsRestUserAgentPolicy(nextPolicy, userAgentInfo);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new MsRestUserAgentPolicy(nextPolicy, options, userAgentInfo);
};
}
@ -20,8 +20,8 @@ export class MsRestUserAgentPolicy extends BaseRequestPolicy {
userAgentInfo: Array<string>;
constructor(nextPolicy: RequestPolicy, userAgentInfo: Array<string>) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, userAgentInfo: Array<string>) {
super(nextPolicy, options);
this.userAgentInfo = userAgentInfo;
}

Просмотреть файл

@ -3,11 +3,11 @@
import * as parse from "url-parse";
import { HttpOperationResponse } from "../httpOperationResponse";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicy, RequestPolicyCreator } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicy, RequestPolicyCreator, RequestPolicyOptions } from "./requestPolicy";
export function redirectPolicy(maximumRetries = 20): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new RedirectPolicy(nextPolicy, maximumRetries);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new RedirectPolicy(nextPolicy, options, maximumRetries);
};
}
@ -15,8 +15,8 @@ export class RedirectPolicy extends BaseRequestPolicy {
maximumRetries?: number;
constructor(nextPolicy: RequestPolicy, maximumRetries = 20) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, maximumRetries = 20) {
super(nextPolicy, options);
this.maximumRetries = maximumRetries;
}

Просмотреть файл

@ -2,20 +2,72 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
import { HttpOperationResponse } from "../httpOperationResponse";
import { HttpPipelineLogLevel } from "../httpPipelineLogLevel";
import { HttpPipelineLogger } from "../httpPipelineLogger";
import { WebResource } from "../webResource";
/**
* A function that creates a new RequestPolicy that uses the provided nextPolicy.
*/
export type RequestPolicyCreator = (nextPolicy: RequestPolicy) => RequestPolicy;
export type RequestPolicyCreator = (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => RequestPolicy;
export interface RequestPolicy {
sendRequest(httpRequest: WebResource): Promise<HttpOperationResponse>;
}
export abstract class BaseRequestPolicy implements RequestPolicy {
protected constructor(protected readonly _nextPolicy: RequestPolicy) {
protected constructor(protected readonly _nextPolicy: RequestPolicy, protected readonly _options: RequestPolicyOptions) {
}
public abstract sendRequest(webResource: WebResource): Promise<HttpOperationResponse>;
/**
* Get whether or not a log with the provided log level should be logged.
* @param logLevel The log level of the log that will be logged.
* @returns Whether or not a log with the provided log level should be logged.
*/
public shouldLog(logLevel: HttpPipelineLogLevel): boolean {
return this._options.shouldLog(logLevel);
}
/**
* Attempt to log the provided message to the provided logger. If no logger was provided or if
* the log level does not meat the logger's threshold, then nothing will be logged.
* @param logLevel The log level of this log.
* @param message The message of this log.
*/
public log(logLevel: HttpPipelineLogLevel, message: string): void {
this._options.log(logLevel, message);
}
}
/**
* Optional properties that can be used when creating a RequestPolicy.
*/
export class RequestPolicyOptions {
constructor(private _logger?: HttpPipelineLogger) {
}
/**
* Get whether or not a log with the provided log level should be logged.
* @param logLevel The log level of the log that will be logged.
* @returns Whether or not a log with the provided log level should be logged.
*/
public shouldLog(logLevel: HttpPipelineLogLevel): boolean {
return !!this._logger &&
logLevel !== HttpPipelineLogLevel.OFF &&
logLevel <= this._logger.minimumLogLevel;
}
/**
* Attempt to log the provided message to the provided logger. If no logger was provided or if
* the log level does not meat the logger's threshold, then nothing will be logged.
* @param logLevel The log level of this log.
* @param message The message of this log.
*/
public log(logLevel: HttpPipelineLogLevel, message: string): void {
if (this._logger && this.shouldLog(logLevel)) {
this._logger.log(logLevel, message);
}
}
}

Просмотреть файл

@ -3,22 +3,22 @@
import { HttpOperationResponse } from "../httpOperationResponse";
import * as utils from "../util/utils";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy, RequestPolicyOptions } from "./requestPolicy";
/* tslint:disable:prefer-const */
let retryTimeout = 30;
/* tslint:enable:prefer-const */
export function rpRegistrationPolicy(retryTimeout = 30): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new RPRegistrationPolicy(nextPolicy, retryTimeout);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new RPRegistrationPolicy(nextPolicy, options, retryTimeout);
};
}
export class RPRegistrationPolicy extends BaseRequestPolicy {
constructor(nextPolicy: RequestPolicy, retryTimeout = 30) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, retryTimeout = 30) {
super(nextPolicy, options);
retryTimeout = retryTimeout;
}

Просмотреть файл

@ -4,18 +4,18 @@
import { ServiceClientCredentials } from "../credentials/serviceClientCredentials";
import { HttpOperationResponse } from "../httpOperationResponse";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicyCreator, RequestPolicy, RequestPolicyOptions } from "./requestPolicy";
export function signingPolicy(authenticationProvider: ServiceClientCredentials): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new SigningPolicy(nextPolicy, authenticationProvider);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new SigningPolicy(nextPolicy, options, authenticationProvider);
};
}
export class SigningPolicy extends BaseRequestPolicy {
constructor(nextPolicy: RequestPolicy, public authenticationProvider: ServiceClientCredentials) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, public authenticationProvider: ServiceClientCredentials) {
super(nextPolicy, options);
}
before(request: WebResource): Promise<WebResource> {

Просмотреть файл

@ -4,7 +4,7 @@
import { HttpOperationResponse } from "../httpOperationResponse";
import * as utils from "../util/utils";
import { WebResource } from "../webResource";
import { BaseRequestPolicy, RequestPolicy, RequestPolicyCreator } from "./requestPolicy";
import { BaseRequestPolicy, RequestPolicy, RequestPolicyCreator, RequestPolicyOptions } from "./requestPolicy";
export interface RetryData {
retryCount: number;
@ -19,8 +19,8 @@ export interface RetryError extends Error {
}
export function systemErrorRetryPolicy(retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number): RequestPolicyCreator {
return (nextPolicy: RequestPolicy) => {
return new SystemErrorRetryPolicy(nextPolicy, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new SystemErrorRetryPolicy(nextPolicy, options, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
};
}
@ -45,8 +45,8 @@ export class SystemErrorRetryPolicy extends BaseRequestPolicy {
DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90;
DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3;
constructor(nextPolicy: RequestPolicy, retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number) {
super(nextPolicy);
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions, retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number) {
super(nextPolicy, options);
this.retryCount = typeof retryCount === "number" ? retryCount : this.DEFAULT_CLIENT_RETRY_COUNT;
this.retryInterval = typeof retryInterval === "number" ? retryInterval : this.DEFAULT_CLIENT_RETRY_INTERVAL;
this.minRetryInterval = typeof minRetryInterval === "number" ? minRetryInterval : this.DEFAULT_CLIENT_MIN_RETRY_INTERVAL;

Просмотреть файл

@ -8,12 +8,13 @@ import { HttpOperationResponse } from "./httpOperationResponse";
import { exponentialRetryPolicy } from "./policies/exponentialRetryPolicy";
import { msRestUserAgentPolicy } from "./policies/msRestUserAgentPolicy";
import { redirectPolicy } from "./policies/redirectPolicy";
import { RequestPolicy, RequestPolicyCreator } from "./policies/requestPolicy";
import { RequestPolicy, RequestPolicyCreator, RequestPolicyOptions } from "./policies/requestPolicy";
import { rpRegistrationPolicy } from "./policies/rpRegistrationPolicy";
import { signingPolicy } from "./policies/signingPolicy";
import { systemErrorRetryPolicy } from "./policies/systemErrorRetryPolicy";
import { Constants } from "./util/constants";
import { RequestPrepareOptions, WebResource } from "./webResource";
import { HttpPipelineLogger } from "./httpPipelineLogger";
/**
* Options to be provided while creating the client.
@ -34,6 +35,11 @@ export interface ServiceClientOptions {
* @property {HttpClient} [httpClient] - The HttpClient that will be used to send HTTP requests.
*/
httpClient?: HttpClient;
/**
* @property {HttpPipelineLogger} [httpPipelineLogger] - The HttpPipelineLogger that can be used
* to debug RequestPolicies within the HTTP pipeline.
*/
httpPipelineLogger?: HttpPipelineLogger;
/**
* @property {bool} [noRetryPolicy] - If set to true, turn off the default retry policy.
*/
@ -61,6 +67,7 @@ export class ServiceClient {
* The HTTP client that will be used to send requests.
*/
private readonly _httpClient: HttpClient;
private readonly _requestPolicyOptions: RequestPolicyOptions;
private readonly _requestPolicyCreators: RequestPolicyCreator[];
@ -95,6 +102,7 @@ export class ServiceClient {
}
this._httpClient = options.httpClient || new FetchHttpClient();
this._requestPolicyOptions = new RequestPolicyOptions(options.httpPipelineLogger);
this._requestPolicyCreators = options.requestPolicyCreators || createDefaultRequestPolicyCreators(credentials, options, this.userAgentInfo.value);
}
@ -103,7 +111,7 @@ export class ServiceClient {
let httpPipeline: RequestPolicy = this._httpClient;
if (this._requestPolicyCreators && this._requestPolicyCreators.length > 0) {
for (let i = this._requestPolicyCreators.length - 1; i >= 0; --i) {
httpPipeline = this._requestPolicyCreators[i](httpPipeline);
httpPipeline = this._requestPolicyCreators[i](httpPipeline, this._requestPolicyOptions);
}
}
return httpPipeline.sendRequest(request);

Просмотреть файл

@ -6,7 +6,7 @@ import { Response } from "node-fetch";
import { LogPolicy } from "../lib/policies/logPolicy";
import { HttpOperationResponse } from "../lib/httpOperationResponse";
import { WebResource } from "../lib/webResource";
import { RequestPolicy } from "../lib/policies/requestPolicy";
import { RequestPolicy, RequestPolicyOptions } from "../lib/policies/requestPolicy";
const emptyRequestPolicy: RequestPolicy = {
sendRequest(request: WebResource): Promise<HttpOperationResponse> {
@ -32,7 +32,7 @@ describe("Log filter", () => {
`;
let output = "";
const logger = (message: string): void => { output += message + "\n"; };
const lf = new LogPolicy(emptyRequestPolicy, logger);
const lf = new LogPolicy(emptyRequestPolicy, new RequestPolicyOptions(), logger);
const req = new WebResource("https://foo.com", "PUT", { "a": 1 });
const res = new Response();
const opRes = new HttpOperationResponse(req, res as any);

Просмотреть файл

@ -5,7 +5,7 @@ import * as assert from "assert";
import { WebResource } from "../lib/webResource";
import { MsRestUserAgentPolicy } from "../lib/policies/msRestUserAgentPolicy";
import { Constants } from "../lib/util/constants";
import { RequestPolicy } from "../lib/policies/requestPolicy";
import { RequestPolicy, RequestPolicyOptions } from "../lib/policies/requestPolicy";
import { HttpOperationResponse } from "../lib/httpOperationResponse";
import { isNode } from "../lib/util/utils";
@ -26,7 +26,7 @@ describe("ms-rest user agent filter (nodejs only)", () => {
}
const userAgentArray: Array<string> = [];
const userAgentFilter = new MsRestUserAgentPolicy(emptyRequestPolicy, userAgentArray);
const userAgentFilter = new MsRestUserAgentPolicy(emptyRequestPolicy, new RequestPolicyOptions(), userAgentArray);
const resource = new WebResource();
resource.headers = {};
userAgentFilter.before(resource).then((resource) => {
@ -46,7 +46,7 @@ describe("ms-rest user agent filter (nodejs only)", () => {
const azureRuntime = "ms-rest-azure";
const azureSDK = "Azure-SDK-For-Node";
const userAgentArray = [`${genericRuntime}/v1.0.0`, `${azureRuntime}/v1.0.0`];
const userAgentFilter = new MsRestUserAgentPolicy(emptyRequestPolicy, userAgentArray);
const userAgentFilter = new MsRestUserAgentPolicy(emptyRequestPolicy, new RequestPolicyOptions(), userAgentArray);
const customUA = "my custom user agent";
const resource = new WebResource();
resource.headers = {};
@ -71,7 +71,7 @@ describe("ms-rest user agent filter (nodejs only)", () => {
const azureRuntime = "ms-rest-azure";
const azureSDK = "Azure-SDK-For-Node";
const userAgentArray = [`${genericRuntime}/v1.0.0`, `${azureRuntime}/v1.0.0`];
const userAgentFilter = new MsRestUserAgentPolicy(emptyRequestPolicy, userAgentArray);
const userAgentFilter = new MsRestUserAgentPolicy(emptyRequestPolicy, new RequestPolicyOptions(), userAgentArray);
const resource = new WebResource();
resource.headers = {};
userAgentFilter.before(resource).then((resource) => {