Skip to content

Commit

Permalink
refactor: split API in multiple sub-class (#84)
Browse files Browse the repository at this point in the history
* refactor: split API in multiple sub-class

* docs: use CAUTION blockquote
  • Loading branch information
fraxken authored Nov 23, 2023
1 parent 691a21e commit dd01f4e
Showing 15 changed files with 908 additions and 579 deletions.
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -3,5 +3,8 @@
"parserOptions": {
"sourceType": "module",
"requireConfigFile": false
},
"rules": {
"func-style": "off"
}
}
252 changes: 19 additions & 233 deletions README.md
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
</h1></p>

<p align="center">
Node.js Grafana Loki SDK
Node.js Grafana API SDK (Loki, Datasources ..)
</p>

<p align="center">
@@ -41,20 +41,19 @@ $ yarn add @myunisoft/loki
## 📚 Usage

```ts
import { GrafanaLoki } from "@myunisoft/loki";
import { LogQL } from "@sigyn/logql";
import { GrafanaApi } from "@myunisoft/loki";
import { LogQL, StreamSelector } from "@sigyn/logql";

const api = new GrafanaLoki({
const api = new GrafanaApi({
// Note: if not provided, it will load process.env.GRAFANA_API_TOKEN
apiToken: "...",
remoteApiURL: "https://name.loki.com"
});

const ql = new LogQL();
ql.streamSelector.set("app", "serviceName");
ql.streamSelector.set("env", "production");

const logs = await api.queryRange(
const ql = new LogQL(
new StreamSelector({ app: "serviceName", env: "production" })
);
const logs = await api.Loki.queryRange(
ql, // or string `{app="serviceName", env="production"}`
{
start: "1d",
@@ -64,242 +63,29 @@ const logs = await api.queryRange(
console.log(logs);
```

queryRange options is described by the following TypeScript interface
```ts
export interface LokiQueryOptions<T> {
/**
* @default 100
*/
limit?: number;
start?: number | string;
end?: number | string;
since?: string;
parser?: LogParserLike<T>;
}
```

<em>start</em> and <em>end</em> arguments can be either a unix timestamp or a duration like `6h`.

## API

### queryRange

You can provide a custom parser to queryRange (by default it inject a NoopParser doing nothing).

```ts
import { LogParser } from "@myunisoft/loki";

interface CustomParser {
date: string;
requestId: string;
endpoint: string;
method: string;
statusCode: number;
}

const customParser = new LogParser<CustomParser>(
"<date>: [req-<requestId:word>] <endpoint> <method:httpMethod> <statusCode:httpStatusCode>"
);

const logs = await api.queryRange(
`{app="serviceName", env="production"}`,
{
parser: customParser
}
);
for (const data of logs) {
console.log(`requestId: ${data.requestId}`);
}
```

### queryRangeStream

Same as `queryRange` but returns the labels key-value pairs stream
### GrafanaAPI

```ts
const customParser = new LogParser<CustomParser>(
"<date>: [req-<requestId:word>] <endpoint> <method:httpMethod> <statusCode:httpStatusCode>"
);

const logs = await api.queryRangeStream(
`{app="serviceName", env="production"}`,
);
for (const { stream, values } of logs) {
// Record<string, string>
console.log(stream);
// string[]
console.log(values);
}

interface LokiStreamResult<T = string> {
stream: Record<string, string>;
values: T[];
}
```

### datasources

```ts
interface LokiDatasource {
id: number;
uid: string;
orgId: number;
name: string;
type: string;
typeName?: string;
typeLogoUrl: string;
access: string;
url: string;
password?: string;
user: string;
database: string;
basicAuth: boolean;
basicAuthUser?: string;
basicAuthPassword?: string;
withCredentials?: boolean;
isDefault: boolean;
jsonData?: {
authType?: string;
defaultRegion?: string;
logLevelField?: string;
logMessageField?: string;
timeField?: string;
maxConcurrentShardRequests?: number;
maxLines?: number;
graphiteVersion?: string;
graphiteType?: string;
};
secureJsonFields?: {
basicAuthPassword?: boolean;
};
version?: number;
readOnly: boolean;
}
```

```ts
const datasources = await api.datasources();
```

`datasources()` retrieves all datasources.

### datasourceById

```ts
const datasource = await api.datasourceById(1);
// or
const datasource = await api.datasourceById("1");
```

`datasourceById(id: number | string)` retrieves a single datasource given it's id.

### datasourceByName

```ts
const datasource = await api.datasourceByName("Loki");
```

`datasourceByName(name: string)` retrieves a single datasource given it's name.

### datasourceByUid

```ts
const datasource = await api.datasourceByUid("303030xGz");
```

`datasourceByUid(name: string)` retrieves a single datasources given it's uid.

### datasourceIdByName

```ts
const id = await api.datasourceIdByName("Loki");
```

`datasourceIdByName(name: string)` retrieves datasource id given it's name.

### labels

```ts
const labels = await api.labels();
```

`labels(options = {})` retrieves the list of known labels within a given time span. Loki may use a larger time span than the one specified. It accepts the following options:

```ts
interface LokiLabelsOptions {
export interface GrafanaApiOptions {
/**
* The start time for the query as
* - a nanosecond Unix epoch.
* - a duration (i.e "2h")
*
* Default to 6 hours ago.
* Grafana API Token
*/
start?: number | string;
apiToken?: string;
/**
* The end time for the query as
* - a nanosecond Unix epoch.
* - a duration (i.e "2h")
*
* Default to now
* Remote Grafana root API URL
*/
end?: number | string;
/**
* A duration used to calculate start relative to end. If end is in the future, start is calculated as this duration before now.
*
* Any value specified for start supersedes this parameter.
*/
since?: string;
}
```

### labelValues

```ts
const appLabelValues = await api.labelValues("app");
```

`labelValues(label, options = {})` retrieves the list of known values for a given label within a given time span. Loki may use a larger time span than the one specified.

```ts
interface LokiLabelValueOptions {
/**
* The start time for the query as
* - a nanosecond Unix epoch.
* - a duration (i.e "2h")
*
* Default to 6 hours ago.
*/
start?: number | string;
/**
* The end time for the query as
* - a nanosecond Unix epoch.
* - a duration (i.e "2h")
*
* Default to now
*/
end?: number | string;
/**
* A duration used to calculate start relative to end. If end is in the future, start is calculated as this duration before now.
*
* Any value specified for start supersedes this parameter.
*/
since?: string;
/**
* A set of log stream selector that selects the streams to match and return label values for <name>.
*
* Example: {"app": "myapp", "environment": "dev"}
*/
query?: string;
}
remoteApiURL: string | URL;
}s
```

### series
### Sub-class

```ts
const series = await api.series(`{env="production"}`);
```
- [Loki](./docs/Loki.md)
- [Datasources](./docs/Datasources.md)

Returns the list of time series that match a certain label set.
You can also parse logs using our internal [LogParser](./docs/LogParser.md) implementation.

## Contributors ✨

93 changes: 93 additions & 0 deletions docs/Datasources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Grafana Datasources API

https://grafana.com/docs/grafana/latest/developers/http_api/data_source/

API are accessible from the `Datasources` property.

```ts
import { GrafanaApi } from "@myunisoft/loki";

const api = new GrafanaApi({
remoteApiURL: "https://name.loki.com"
});

await api.Datasources.all();
```

Datasource is described by the following TypeScript interface
```ts
interface Datasource {
id: number;
uid: string;
orgId: number;
name: string;
type: string;
typeName?: string;
typeLogoUrl: string;
access: string;
url: string;
password?: string;
user: string;
database: string;
basicAuth: boolean;
basicAuthUser?: string;
basicAuthPassword?: string;
withCredentials?: boolean;
isDefault: boolean;
jsonData?: {
authType?: string;
defaultRegion?: string;
logLevelField?: string;
logMessageField?: string;
timeField?: string;
maxConcurrentShardRequests?: number;
maxLines?: number;
graphiteVersion?: string;
graphiteType?: string;
};
secureJsonFields?: {
basicAuthPassword?: boolean;
};
version?: number;
readOnly: boolean;
}
```

## API

### all(): Promise< Datasource[] >
retrieves all datasources.

```ts
const datasources = await api.Datasources.all();
```

### byId(id: number | string): Promise< Datasource >
retrieves a single datasource given it's id.

```ts
const datasource = await api.Datasources.byId(1);
// or
const datasource = await api.Datasources.byId("1");
```

### byName(name: string): Promise< Datasource >
retrieves a single datasource given it's name.

```ts
const datasource = await api.Datasources.byName("Loki");
```

### byUID(name: string): Promise< Datasource >
retrieves a single datasources given it's uid.

```ts
const datasource = await api.Datasources.byUID("303030xGz");
```

### idByName(name: string): Promise< Datasource >
retrieves datasource id given it's name.

```ts
const id = await api.Datasources.idByName("Loki");
```
Loading

0 comments on commit dd01f4e

Please sign in to comment.