Skip to content

Commit

Permalink
Merge pull request #122 from thiagobustamante/master
Browse files Browse the repository at this point in the history
log proxy time / support load middlewares installed globally
  • Loading branch information
thiagobustamante committed Mar 26, 2018
2 parents 8b1749f + 4cfb926 commit bfd8456
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 9 deletions.
45 changes: 38 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ It provides:
- **Integrated CircuitBreaker** - A fast [circuitbreaker](https://martinfowler.com/bliki/CircuitBreaker.html) to fast fail your responses when your API is having problems to work. It support custom handlers for events like "open" or "close" circuit.
- Real Time **Monitoring and Analytics** -
- Collect statistics about any access to your APIs. Capture any event, like a cache hit on a cache entrance, a circuitbreaker open circuit or an authentication attempt.
- A very flexible and powerfull log system, that can be integrated with any service like logstash, loggly or new relic.
- A very flexible and powerfull log system, that can be integrated with any service like logstash, timescale, loggly or new relic.
- **Easy Administration** - The gateway can be configured remotelly. And no restart is needed. Any API configuration can be "hot" changed and all configurations are propagated to other tree-gateway cluster nodes with no pain. The gateway can be configured through:
- Admin API - A REST API that can be invoked through HTTP;
- SDK - A Node JS SDK that can be used to configure the Gateway (or a cluster of gateways) programmatically;
Expand All @@ -49,16 +49,47 @@ It provides:
<a href="https://www.youtube.com/watch?v=FkAeEmt2wro"><img src="https://img.youtube.com/vi/FkAeEmt2wro/1.jpg"/></a>


## Try Tree Gateway
## Quick Start

Install the gateway:

```sh
npm install -g tree-gateway
```

Run it:

```sh
treeGateway
```

Then map your first API. Just create an YML file (my-api.yaml):

```yaml
---
name: Test
version: 1.0.0
path: "/test"
proxy:
target:
host: http://httpbin.org
timeout: five seconds
```

And use the Tree Gateway CLI to configure it into the gateway:

```sh
treeGatewayConfig apis --add ./my-api.yaml
```

And its done. You can test it accessing in your browser: `http://localhost:8000/test/get`


## Gateway Configuration Reference

Take a better look into Tree Gateway by checking out the project and working with it guided by our [Docs](https://github.com/Leanty/tree-gateway/wiki).

## Check out the Dashboard!

<p align="center">
<a href="http://dashboard.leanty.com/"><img src="http://treegateway.org/img/slide/example-slide-1.png" /><a/>
</p>

## Migrating from previous versions

Check our [migration guide](https://github.com/Leanty/tree-gateway/wiki/migrationGuide).
18 changes: 18 additions & 0 deletions src/pipeline/proxy/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { MiddlewareLoader } from '../../utils/middleware-loader';
import { ServiceDiscovery } from '../servicediscovery/service-discovery';
import { WritableStreamBuffer } from 'stream-buffers';
import { ApiPipelineConfig } from '../../config/gateway';
import { RequestLogger } from '../stats/request';
const agentKeepAlive = require('agentkeepalive');
const httpProxy = require('../../../lib/http-proxy');

Expand All @@ -26,6 +27,7 @@ export class ApiProxy {
@Inject private logger: Logger;
@Inject private middlewareLoader: MiddlewareLoader;
@Inject private serviceDiscovery: ServiceDiscovery;
@Inject private requestLogger: RequestLogger;

/**
* Configure a proxy for a given API
Expand Down Expand Up @@ -103,7 +105,12 @@ export class ApiProxy {
}

const proxy = httpProxy.createProxyServer(proxyConfig);
const requestLogEnabled = this.requestLogger.isRequestLogEnabled(api);
proxy.on('error', (err: any, req: express.Request, res: express.Response) => {
if (requestLogEnabled) {
const requestLog = this.requestLogger.getRequestLog(req);
requestLog.proxyTime -= new Date().getTime();
}
const hostname = (req.headers && req.headers.host) || (req.hostname || req.host); // (websocket) || (node0.10 || node 4/5)
const target = apiProxy.target.host;
const errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page
Expand All @@ -113,6 +120,12 @@ export class ApiProxy {
res.status(502).send('Bad Gateway');
}
});
if (requestLogEnabled) {
proxy.on('start', (req: express.Request, res: express.Response) => {
const requestLog = this.requestLogger.getRequestLog(req);
requestLog.proxyTime = new Date().getTime();
});
}

const maybeWrapResponse = this.interceptor.hasResponseInterceptor(api);
const responseInterceptor: ResponseInterceptors = this.interceptor.buildResponseInterceptors(api, pipelineConfig);
Expand Down Expand Up @@ -147,7 +160,12 @@ export class ApiProxy {
}

private handleResponseInterceptor(api: ApiConfig, proxy: any, responseInterceptor: ResponseInterceptors) {
const requestLogEnabled = this.requestLogger.isRequestLogEnabled(api);
proxy.on('end', (req: any, res: any, proxyRes: any, ) => {
if (requestLogEnabled) {
const requestLog = this.requestLogger.getRequestLog(req);
requestLog.proxyTime -= new Date().getTime();
}
if (res.__data) {
if (responseInterceptor) {
responseInterceptor.middelware(res.__data.getContents(), proxyRes, req, res, res.__ignore,
Expand Down
1 change: 1 addition & 0 deletions src/pipeline/stats/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface RequestLog {
ip: string;
method: string;
path: string;
proxyTime: number;
responseTime: number;
status: number;
timestamp: number;
Expand Down
7 changes: 6 additions & 1 deletion src/utils/middleware-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ export class MiddlewareLoader {
p = path.join(this.config.middlewarePath, type, middlewareId);
}

let middleware = require(p);
let middleware;
try {
middleware = require(p);
} catch(e) {
middleware = require(middlewareId);
}
if (middleware.factory) {
middleware = middleware(middlewareConfig.options || {});
}
Expand Down
19 changes: 19 additions & 0 deletions src/utils/time-intervals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@
import * as _ from 'lodash';
const humanInterval = require('human-interval');

humanInterval.languageMap['eleven'] = 11;
humanInterval.languageMap['twelve'] = 12;
humanInterval.languageMap['thirteen'] = 13;
humanInterval.languageMap['fourteen'] = 14;
humanInterval.languageMap['fifteen'] = 15;
humanInterval.languageMap['sixteen'] = 16;
humanInterval.languageMap['seventeen'] = 17;
humanInterval.languageMap['eighteen'] = 18;
humanInterval.languageMap['nineteen'] = 19;
humanInterval.languageMap['twenty'] = 20;
humanInterval.languageMap['thirty'] = 30;
humanInterval.languageMap['fourty'] = 40;
humanInterval.languageMap['fifty'] = 50;
humanInterval.languageMap['sixty'] = 60;
humanInterval.languageMap['seventy'] = 70;
humanInterval.languageMap['eighty'] = 80;
humanInterval.languageMap['ninety'] = 90;
humanInterval.languageMap['hundred'] = 100;

export function getMilisecondsInterval(value: string | number | undefined, defaultValue?: number) {
if (!value) {
return defaultValue;
Expand Down
2 changes: 1 addition & 1 deletion test/data/apis/authenticated.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"target": {
"host": "http://httpbin.org"
},
"timeout": "five seconds"
"timeout": "fifteen seconds"
},
"parseCookies": true,
"authentication": {
Expand Down

0 comments on commit bfd8456

Please sign in to comment.