Add vlogs sdk for ts
This commit is contained in:
commit
430d052865
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dist/
|
||||||
|
build/
|
||||||
|
node_modules/
|
31
README.md
Normal file
31
README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# vLogs SDK for JS/TS
|
||||||
|
|
||||||
|
A simple way to collect logs and send to the server via simple SDK.
|
||||||
|
|
||||||
|
- [x] Collect the logs
|
||||||
|
- [ ] Support local retries
|
||||||
|
|
||||||
|
## Usages
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const APP_ID = 'xxx';
|
||||||
|
const API_KEY = 'vlogs_xxx';
|
||||||
|
|
||||||
|
const sdk = VLogs.create(
|
||||||
|
VLogsOptions.builder().appId(APP_ID).apiKey(API_KEY).build()
|
||||||
|
);
|
||||||
|
|
||||||
|
const request = Collector.builder()
|
||||||
|
.message('Hello from vlogs-ts-sdk')
|
||||||
|
.type(CollectorType.Log)
|
||||||
|
.source(CollectorSource.Web)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
const response = await sdk.collect(request);
|
||||||
|
console.log('Request: ', request);
|
||||||
|
console.log('Response: ', response);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
- Sambo Chea <sombochea@cubetiqs.com>
|
9
jest.config.js
Normal file
9
jest.config.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
modulePathIgnorePatterns: ['<rootDir>/dist/'],
|
||||||
|
testPathIgnorePatterns: ["/node_modules/"],
|
||||||
|
moduleNameMapper: {
|
||||||
|
"\\.(css|less)$": "identity-obj-proxy"
|
||||||
|
}
|
||||||
|
};
|
3687
package-lock.json
generated
Normal file
3687
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
package.json
Normal file
42
package.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "@cubetiq/vlogs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A simple way to collect logs and send to the server via simple SDK.",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"dist": {
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"dev": "tsc -w",
|
||||||
|
"start": "node dist/index.js",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/CUBETIQ/vlogs_sdk_ts.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vlogs"
|
||||||
|
],
|
||||||
|
"author": "Sambo Chea <sombochea@cubetiqs.com>",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/CUBETIQ/vlogs_sdk_ts/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/CUBETIQ/vlogs_sdk_ts#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.1",
|
||||||
|
"@types/node": "^20.2.5",
|
||||||
|
"@types/uuid": "^9.0.1",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"typescript": "^5.0.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.4.0",
|
||||||
|
"uuid": "^9.0.0"
|
||||||
|
}
|
||||||
|
}
|
2
src/index.ts
Normal file
2
src/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './model'
|
||||||
|
export * from './vlgos'
|
692
src/model.ts
Normal file
692
src/model.ts
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
import { generateUUID } from "./util";
|
||||||
|
|
||||||
|
enum CollectorType {
|
||||||
|
Error,
|
||||||
|
Event,
|
||||||
|
Metric,
|
||||||
|
Trace,
|
||||||
|
Log,
|
||||||
|
Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CollectorSource {
|
||||||
|
Web,
|
||||||
|
Mobile,
|
||||||
|
Server,
|
||||||
|
Desktop,
|
||||||
|
IoT,
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TelegramParseMode {
|
||||||
|
Markdown,
|
||||||
|
MarkdownV2,
|
||||||
|
HTML,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface TelegramOptions {
|
||||||
|
token?: string;
|
||||||
|
chatId?: string;
|
||||||
|
parseMode?: TelegramParseMode;
|
||||||
|
disabled?: boolean;
|
||||||
|
extras?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Telegram {
|
||||||
|
token?: string;
|
||||||
|
chatId?: string;
|
||||||
|
parseMode?: TelegramParseMode;
|
||||||
|
disabled?: boolean;
|
||||||
|
extras?: any;
|
||||||
|
|
||||||
|
constructor(options: TelegramOptions = {}) {
|
||||||
|
this.token = options.token;
|
||||||
|
this.chatId = options.chatId;
|
||||||
|
this.parseMode = options.parseMode;
|
||||||
|
this.disabled = options.disabled;
|
||||||
|
this.extras = options.extras;
|
||||||
|
}
|
||||||
|
|
||||||
|
toMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
'token': this.token,
|
||||||
|
'chat_id': this.chatId,
|
||||||
|
'parse_mode': this.parseMode,
|
||||||
|
'disabled': this.disabled,
|
||||||
|
'extras': this.extras,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static builder(): TelegramBuilder {
|
||||||
|
return new TelegramBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TelegramBuilder {
|
||||||
|
private _token?: string;
|
||||||
|
private _chatId?: string;
|
||||||
|
private _parseMode?: TelegramParseMode;
|
||||||
|
private _disabled?: boolean;
|
||||||
|
private _extras?: any;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
token(token?: string): TelegramBuilder {
|
||||||
|
this._token = token;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatId(chatId?: string): TelegramBuilder {
|
||||||
|
this._chatId = chatId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMode(parseMode?: TelegramParseMode): TelegramBuilder {
|
||||||
|
this._parseMode = parseMode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled(disabled?: boolean): TelegramBuilder {
|
||||||
|
this._disabled = disabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
extras(extras?: any): TelegramBuilder {
|
||||||
|
this._extras = extras;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): Telegram {
|
||||||
|
return new Telegram({
|
||||||
|
token: this._token,
|
||||||
|
chatId: this._chatId,
|
||||||
|
parseMode: this._parseMode,
|
||||||
|
disabled: this._disabled,
|
||||||
|
extras: this._extras,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Discord {
|
||||||
|
webhookId?: string;
|
||||||
|
webhookToken?: string;
|
||||||
|
webhookUrl?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
extras?: any;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
webhookId,
|
||||||
|
webhookToken,
|
||||||
|
webhookUrl,
|
||||||
|
disabled,
|
||||||
|
extras,
|
||||||
|
}: {
|
||||||
|
webhookId?: string;
|
||||||
|
webhookToken?: string;
|
||||||
|
webhookUrl?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
extras?: any;
|
||||||
|
}) {
|
||||||
|
this.webhookId = webhookId;
|
||||||
|
this.webhookToken = webhookToken;
|
||||||
|
this.webhookUrl = webhookUrl;
|
||||||
|
this.disabled = disabled;
|
||||||
|
this.extras = extras;
|
||||||
|
}
|
||||||
|
|
||||||
|
toMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
webhook_id: this.webhookId,
|
||||||
|
webhook_token: this.webhookToken,
|
||||||
|
webhook_url: this.webhookUrl,
|
||||||
|
disabled: this.disabled,
|
||||||
|
extras: this.extras,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static builder(): DiscordBuilder {
|
||||||
|
return new DiscordBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DiscordBuilder {
|
||||||
|
private _webhookId?: string;
|
||||||
|
private _webhookToken?: string;
|
||||||
|
private _webhookUrl?: string;
|
||||||
|
private _disabled?: boolean;
|
||||||
|
private _extras?: any;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
webhookId(webhookId: string | undefined): DiscordBuilder {
|
||||||
|
this._webhookId = webhookId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookToken(webhookToken: string | undefined): DiscordBuilder {
|
||||||
|
this._webhookToken = webhookToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookUrl(webhookUrl: string | undefined): DiscordBuilder {
|
||||||
|
this._webhookUrl = webhookUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled(disabled: boolean | undefined): DiscordBuilder {
|
||||||
|
this._disabled = disabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
extras(extras: any): DiscordBuilder {
|
||||||
|
this._extras = extras;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): Discord {
|
||||||
|
return new Discord({
|
||||||
|
webhookId: this._webhookId,
|
||||||
|
webhookToken: this._webhookToken,
|
||||||
|
webhookUrl: this._webhookUrl,
|
||||||
|
disabled: this._disabled,
|
||||||
|
extras: this._extras,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SDKInfo {
|
||||||
|
name?: string;
|
||||||
|
version?: string;
|
||||||
|
versionCode?: string;
|
||||||
|
hostname?: string;
|
||||||
|
sender?: string;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
versionCode,
|
||||||
|
hostname,
|
||||||
|
sender,
|
||||||
|
}: {
|
||||||
|
name?: string;
|
||||||
|
version?: string;
|
||||||
|
versionCode?: string;
|
||||||
|
hostname?: string;
|
||||||
|
sender?: string;
|
||||||
|
}) {
|
||||||
|
this.name = name;
|
||||||
|
this.version = version;
|
||||||
|
this.versionCode = versionCode;
|
||||||
|
this.hostname = hostname;
|
||||||
|
this.sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
toMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
version: this.version,
|
||||||
|
version_code: this.versionCode,
|
||||||
|
hostname: this.hostname,
|
||||||
|
sender: this.sender,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static builder(): SDKInfoBuilder {
|
||||||
|
return new SDKInfoBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SDKInfoBuilder {
|
||||||
|
private _name?: string;
|
||||||
|
private _version?: string;
|
||||||
|
private _versionCode?: string;
|
||||||
|
private _hostname?: string;
|
||||||
|
private _sender?: string;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
name(name: string | undefined): SDKInfoBuilder {
|
||||||
|
this._name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
version(version: string | undefined): SDKInfoBuilder {
|
||||||
|
this._version = version;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
versionCode(versionCode: string | undefined): SDKInfoBuilder {
|
||||||
|
this._versionCode = versionCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname(hostname: string | undefined): SDKInfoBuilder {
|
||||||
|
this._hostname = hostname;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender(sender: string | undefined): SDKInfoBuilder {
|
||||||
|
this._sender = sender;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): SDKInfo {
|
||||||
|
return new SDKInfo({
|
||||||
|
name: this._name,
|
||||||
|
version: this._version,
|
||||||
|
versionCode: this._versionCode,
|
||||||
|
hostname: this._hostname,
|
||||||
|
sender: this._sender,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Target {
|
||||||
|
telegram?: Telegram;
|
||||||
|
discord?: Discord;
|
||||||
|
sdkInfo?: SDKInfo;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
telegram,
|
||||||
|
discord,
|
||||||
|
sdkInfo,
|
||||||
|
}: {
|
||||||
|
telegram?: Telegram;
|
||||||
|
discord?: Discord;
|
||||||
|
sdkInfo?: SDKInfo;
|
||||||
|
}) {
|
||||||
|
this.telegram = telegram;
|
||||||
|
this.discord = discord;
|
||||||
|
this.sdkInfo = sdkInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
toMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
telegram: this.telegram?.toMap(),
|
||||||
|
discord: this.discord?.toMap(),
|
||||||
|
sdk_info: this.sdkInfo?.toMap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
merge(defaultTarget?: Target): void {
|
||||||
|
if (!defaultTarget) return;
|
||||||
|
this.telegram ||= defaultTarget.telegram;
|
||||||
|
this.discord ||= defaultTarget.discord;
|
||||||
|
}
|
||||||
|
|
||||||
|
static withTelegram(
|
||||||
|
chatId: string,
|
||||||
|
{
|
||||||
|
token,
|
||||||
|
parseMode,
|
||||||
|
disabled,
|
||||||
|
extras,
|
||||||
|
}: {
|
||||||
|
token?: string;
|
||||||
|
parseMode?: TelegramParseMode;
|
||||||
|
disabled?: boolean;
|
||||||
|
extras?: any;
|
||||||
|
} = {}
|
||||||
|
): Target {
|
||||||
|
return new Target({
|
||||||
|
telegram: new Telegram({
|
||||||
|
chatId,
|
||||||
|
token,
|
||||||
|
parseMode,
|
||||||
|
disabled,
|
||||||
|
extras,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static withDiscord(
|
||||||
|
webhookUrl: string,
|
||||||
|
{
|
||||||
|
webhookId,
|
||||||
|
webhookToken,
|
||||||
|
disabled,
|
||||||
|
extras,
|
||||||
|
}: {
|
||||||
|
webhookId?: string;
|
||||||
|
webhookToken?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
extras?: any;
|
||||||
|
}
|
||||||
|
): Target {
|
||||||
|
return new Target({
|
||||||
|
discord: new Discord({
|
||||||
|
webhookUrl,
|
||||||
|
webhookId,
|
||||||
|
webhookToken,
|
||||||
|
disabled,
|
||||||
|
extras,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static builder(): TargetBuilder {
|
||||||
|
return new TargetBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TargetBuilder {
|
||||||
|
private _telegram?: Telegram;
|
||||||
|
private _discord?: Discord;
|
||||||
|
private _sdkInfo?: SDKInfo;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
telegram(telegram?: Telegram): TargetBuilder {
|
||||||
|
this._telegram = telegram;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
discord(discord?: Discord): TargetBuilder {
|
||||||
|
this._discord = discord;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdkInfo(sdkInfo?: SDKInfo): TargetBuilder {
|
||||||
|
this._sdkInfo = sdkInfo;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): Target {
|
||||||
|
return new Target({
|
||||||
|
telegram: this._telegram,
|
||||||
|
discord: this._discord,
|
||||||
|
sdkInfo: this._sdkInfo,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Collector {
|
||||||
|
id?: string;
|
||||||
|
type?: string;
|
||||||
|
source?: string;
|
||||||
|
message?: string;
|
||||||
|
data?: any;
|
||||||
|
userAgent?: string;
|
||||||
|
timestamp?: number;
|
||||||
|
target?: Target;
|
||||||
|
tags?: string[];
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
source,
|
||||||
|
message,
|
||||||
|
data,
|
||||||
|
userAgent,
|
||||||
|
timestamp,
|
||||||
|
target,
|
||||||
|
tags,
|
||||||
|
}: {
|
||||||
|
id?: string;
|
||||||
|
type?: string;
|
||||||
|
source?: string;
|
||||||
|
message?: string;
|
||||||
|
data?: any;
|
||||||
|
userAgent?: string;
|
||||||
|
timestamp?: number;
|
||||||
|
target?: Target;
|
||||||
|
tags?: string[];
|
||||||
|
}) {
|
||||||
|
this.id = id;
|
||||||
|
this.type = type;
|
||||||
|
this.source = source;
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
this.userAgent = userAgent;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.target = target;
|
||||||
|
this.tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
getId(): string | undefined {
|
||||||
|
if (!this.id) {
|
||||||
|
this.id = generateUUID();
|
||||||
|
}
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTimestamp(): number | undefined {
|
||||||
|
if (!this.timestamp) {
|
||||||
|
this.timestamp = Date.now();
|
||||||
|
}
|
||||||
|
return this.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
id: this.getId(),
|
||||||
|
type: this.type,
|
||||||
|
source: this.source,
|
||||||
|
message: this.message,
|
||||||
|
data: this.data,
|
||||||
|
user_agent: this.userAgent,
|
||||||
|
timestamp: this.getTimestamp(),
|
||||||
|
target: this.target?.toMap(),
|
||||||
|
tags: this.tags,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toJson(): string {
|
||||||
|
return JSON.stringify(this.toMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
static builder(): CollectorBuilder {
|
||||||
|
return new CollectorBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectorBuilder {
|
||||||
|
private _id?: string;
|
||||||
|
private _type?: string;
|
||||||
|
private _source?: string;
|
||||||
|
private _message?: string;
|
||||||
|
private _data?: any;
|
||||||
|
private _userAgent?: string;
|
||||||
|
private _timestamp?: number;
|
||||||
|
private _target?: Target;
|
||||||
|
private _tags?: string[];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
id(id: string): CollectorBuilder {
|
||||||
|
this._id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
type(type: string | CollectorType): CollectorBuilder {
|
||||||
|
this._type = type?.toString();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
source(source: string | CollectorSource): CollectorBuilder {
|
||||||
|
this._source = source?.toString();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
message(message: string): CollectorBuilder {
|
||||||
|
this._message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
data(data: any): CollectorBuilder {
|
||||||
|
this._data = data;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
userAgent(userAgent: string): CollectorBuilder {
|
||||||
|
this._userAgent = userAgent;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp(timestamp: number): CollectorBuilder {
|
||||||
|
this._timestamp = timestamp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
target(target: Target): CollectorBuilder {
|
||||||
|
this._target = target;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
tags(tags: string[]): CollectorBuilder {
|
||||||
|
this._tags = tags;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): Collector {
|
||||||
|
return new Collector({
|
||||||
|
id: this._id,
|
||||||
|
type: this._type,
|
||||||
|
source: this._source,
|
||||||
|
message: this._message,
|
||||||
|
data: this._data,
|
||||||
|
userAgent: this._userAgent,
|
||||||
|
timestamp: this._timestamp,
|
||||||
|
target: this._target,
|
||||||
|
tags: this._tags,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectorResponse {
|
||||||
|
message?: string;
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
constructor({ message, id }: { message?: string; id?: string }) {
|
||||||
|
this.message = message;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VLogsOptions {
|
||||||
|
url?: string;
|
||||||
|
appId?: string;
|
||||||
|
apiKey?: string;
|
||||||
|
connectionTimeout?: number;
|
||||||
|
testConnection?: boolean;
|
||||||
|
target?: Target;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
url,
|
||||||
|
appId,
|
||||||
|
apiKey,
|
||||||
|
connectionTimeout,
|
||||||
|
testConnection,
|
||||||
|
target,
|
||||||
|
}: {
|
||||||
|
url?: string;
|
||||||
|
appId?: string;
|
||||||
|
apiKey?: string;
|
||||||
|
connectionTimeout?: number;
|
||||||
|
testConnection?: boolean;
|
||||||
|
target?: Target;
|
||||||
|
}) {
|
||||||
|
this.url = url;
|
||||||
|
this.appId = appId;
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
this.connectionTimeout = connectionTimeout;
|
||||||
|
this.testConnection = testConnection;
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static builder(): VLogsOptionsBuilder {
|
||||||
|
return new VLogsOptionsBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VLogsOptionsBuilder {
|
||||||
|
private _url?: string;
|
||||||
|
private _appId?: string;
|
||||||
|
private _apiKey?: string;
|
||||||
|
private _connectionTimeout?: number;
|
||||||
|
private _testConnection?: boolean;
|
||||||
|
private _target?: Target;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
url(url: string): VLogsOptionsBuilder {
|
||||||
|
this._url = url;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
appId(appId: string): VLogsOptionsBuilder {
|
||||||
|
this._appId = appId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
apiKey(apiKey: string): VLogsOptionsBuilder {
|
||||||
|
this._apiKey = apiKey;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionTimeout(connectionTimeout: number): VLogsOptionsBuilder {
|
||||||
|
this._connectionTimeout = connectionTimeout;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
testConnection(testConnection: boolean): VLogsOptionsBuilder {
|
||||||
|
this._testConnection = testConnection;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
target(target: Target): VLogsOptionsBuilder {
|
||||||
|
this._target = target;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
telegram(telegram: Telegram): VLogsOptionsBuilder {
|
||||||
|
if (!this._target) {
|
||||||
|
this._target = Target.builder().telegram(telegram).build();
|
||||||
|
} else {
|
||||||
|
this._target.telegram = telegram;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
discord(discord: Discord): VLogsOptionsBuilder {
|
||||||
|
if (!this._target) {
|
||||||
|
this._target = Target.builder().discord(discord).build();
|
||||||
|
} else {
|
||||||
|
this._target.discord = discord;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): VLogsOptions {
|
||||||
|
return new VLogsOptions({
|
||||||
|
url: this._url,
|
||||||
|
appId: this._appId,
|
||||||
|
apiKey: this._apiKey,
|
||||||
|
connectionTimeout: this._connectionTimeout,
|
||||||
|
testConnection: this._testConnection,
|
||||||
|
target: this._target,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
Collector,
|
||||||
|
// CollectorBuilder,
|
||||||
|
CollectorResponse,
|
||||||
|
Target,
|
||||||
|
// TargetBuilder,
|
||||||
|
Telegram,
|
||||||
|
// TelegramBuilder,
|
||||||
|
Discord,
|
||||||
|
// DiscordBuilder,
|
||||||
|
SDKInfo,
|
||||||
|
// SDKInfoBuilder,
|
||||||
|
VLogsOptions,
|
||||||
|
// VLogsOptionsBuilder,
|
||||||
|
|
||||||
|
CollectorSource,
|
||||||
|
CollectorType,
|
||||||
|
TelegramParseMode,
|
||||||
|
}
|
37
src/service.ts
Normal file
37
src/service.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { Collector, CollectorResponse } from './model';
|
||||||
|
import axios, { AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
|
class VLogsService {
|
||||||
|
private url: string;
|
||||||
|
|
||||||
|
constructor(baseUrl: string) {
|
||||||
|
this.url = `${baseUrl}/api/v1/collector`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async post(body: any, headers?: any, timeout?: number): Promise<CollectorResponse> {
|
||||||
|
const config: AxiosRequestConfig = {
|
||||||
|
method: 'POST',
|
||||||
|
url: this.url,
|
||||||
|
data: body,
|
||||||
|
headers: headers,
|
||||||
|
timeout: timeout ? timeout * 1000 : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios(config);
|
||||||
|
|
||||||
|
if (
|
||||||
|
response.status === 200 ||
|
||||||
|
response.status === 201 ||
|
||||||
|
response.status === 202
|
||||||
|
) {
|
||||||
|
return await response.data;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to post data to vlogs server with status code: ${response.status} and message: ${response.statusText}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export { VLogsService };
|
35
src/util.ts
Normal file
35
src/util.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export const getSystemHostname = () => {
|
||||||
|
let name = 'localhost';
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
name = window.location.hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if (typeof process !== 'undefined') {
|
||||||
|
// @ts-ignore
|
||||||
|
name = process.env.HOSTNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSystemUsername = () => {
|
||||||
|
let name = 'unknown';
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
name = window.navigator.userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if (typeof process !== 'undefined') {
|
||||||
|
// @ts-ignore
|
||||||
|
name = process.env.USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateUUID = () => {
|
||||||
|
return uuidv4();
|
||||||
|
}
|
86
src/vlgos.ts
Normal file
86
src/vlgos.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { Collector, CollectorResponse, SDKInfo, Target, VLogsOptions } from "./model";
|
||||||
|
import { VLogsService } from "./service";
|
||||||
|
import { getSystemHostname, getSystemUsername } from "./util";
|
||||||
|
|
||||||
|
export class VLogs {
|
||||||
|
private static readonly _logger = console;
|
||||||
|
private static readonly NAME = 'vlogs';
|
||||||
|
private static readonly VERSION = '1.0.0';
|
||||||
|
private static readonly VERSION_CODE = '1';
|
||||||
|
private static readonly DEFAULT_VLOGS_URL = 'https://vlogs-sg1.onrender.com';
|
||||||
|
private static readonly APP_ID_HEADER_PREFIX = 'x-app-id';
|
||||||
|
private static readonly API_KEY_HEADER_PREFIX = 'x-api-key';
|
||||||
|
private static readonly DEFAULT_CONNECT_TIMEOUT = 60; // seconds
|
||||||
|
|
||||||
|
private _options!: VLogsOptions;
|
||||||
|
private _service!: VLogsService;
|
||||||
|
|
||||||
|
constructor(options: VLogsOptions) {
|
||||||
|
if (!options.appId || !options.apiKey) {
|
||||||
|
throw new Error('AppID and ApiKey are required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default options
|
||||||
|
this._options = options;
|
||||||
|
this._options.url ??= VLogs.DEFAULT_VLOGS_URL;
|
||||||
|
|
||||||
|
// Initialize service
|
||||||
|
this._service = new VLogsService(this._options.url);
|
||||||
|
|
||||||
|
VLogs._logger.log(`VLogs: Initialized AppID: ${this._options.appId} | SDK Version: ${VLogs.VERSION}-${VLogs.VERSION_CODE}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async collect(request: Collector): Promise<CollectorResponse> {
|
||||||
|
VLogs._logger.info(`VLogs: Collecting logs for ${request.getId()}`);
|
||||||
|
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
[VLogs.APP_ID_HEADER_PREFIX]: this._options.appId!,
|
||||||
|
[VLogs.API_KEY_HEADER_PREFIX]: this._options.apiKey!,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
const hostname = getSystemHostname();
|
||||||
|
const sender = getSystemUsername();
|
||||||
|
const sdkInfo = SDKInfo.builder()
|
||||||
|
.hostname(hostname)
|
||||||
|
.sender(sender)
|
||||||
|
.name(VLogs.NAME)
|
||||||
|
.version(VLogs.VERSION)
|
||||||
|
.versionCode(VLogs.VERSION_CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (!request.target) {
|
||||||
|
if (this._options.target) {
|
||||||
|
request.target = this._options.target;
|
||||||
|
} else {
|
||||||
|
request.target = Target.builder().build();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this._options.target) {
|
||||||
|
request.target!.merge(this._options.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set SDK info to request
|
||||||
|
request.target!.sdkInfo = sdkInfo;
|
||||||
|
|
||||||
|
// Append user agent to request
|
||||||
|
request.userAgent ??= `vlogs-ts-sdk/${VLogs.VERSION}-${VLogs.VERSION_CODE} (${hostname})`;
|
||||||
|
|
||||||
|
const response = await this._service.post(request.toMap(), headers, this._options.connectionTimeout ?? VLogs.DEFAULT_CONNECT_TIMEOUT);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(options: VLogsOptions): VLogs {
|
||||||
|
return new VLogs(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static createWith(appId: string, apiKey: string): VLogs {
|
||||||
|
return VLogs.create(
|
||||||
|
VLogsOptions.builder()
|
||||||
|
.apiKey(apiKey)
|
||||||
|
.appId(appId)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
59
tests/vlogs.test.ts
Normal file
59
tests/vlogs.test.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { Collector, CollectorSource, CollectorType, VLogs, VLogsOptions } from '../src';
|
||||||
|
|
||||||
|
const APP_ID = '72bd14c306a91fa8a590330e3898ddcc';
|
||||||
|
const API_KEY = 'vlogs_gX9WwSdKatMNdpUClLU0IfCx575tvdoeQ'
|
||||||
|
|
||||||
|
const sdk = VLogs.create(
|
||||||
|
VLogsOptions.builder()
|
||||||
|
.appId(APP_ID)
|
||||||
|
.apiKey(API_KEY)
|
||||||
|
// .target(Target.withTelegram("xxx"))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
test('VLogs sdk should be defined', () => {
|
||||||
|
expect(sdk).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('VLogs sdk should be able to collect logs', async () => {
|
||||||
|
const request = Collector.builder()
|
||||||
|
.message('Hello from vlogs-ts-sdk')
|
||||||
|
.type(CollectorType.Log)
|
||||||
|
.source(CollectorSource.Web)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
const response = await sdk.collect(request);
|
||||||
|
console.log("Request: ", request);
|
||||||
|
console.log("Response: ", response);
|
||||||
|
|
||||||
|
expect(request.getId()).toBeDefined();
|
||||||
|
expect(request.getId()).not.toBeNull();
|
||||||
|
expect(request.getId()).toEqual(response.id);
|
||||||
|
|
||||||
|
expect(response).toBeDefined();
|
||||||
|
expect(response.id).toBeDefined();
|
||||||
|
expect(response.id).not.toBeNull();
|
||||||
|
expect(response.id).not.toBe('');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('VLogs sdk should be able to collect logs with target', async () => {
|
||||||
|
const request = Collector.builder()
|
||||||
|
.message('Hello from vlogs-ts-sdk')
|
||||||
|
.type(CollectorType.Log)
|
||||||
|
.source(CollectorSource.Web)
|
||||||
|
// .target(Target.withTelegram("xxx"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
const response = await sdk.collect(request);
|
||||||
|
console.log("Request: ", request);
|
||||||
|
console.log("Response: ", response);
|
||||||
|
|
||||||
|
expect(request.getId()).toBeDefined();
|
||||||
|
expect(request.getId()).not.toBeNull();
|
||||||
|
expect(request.getId()).toEqual(response.id);
|
||||||
|
|
||||||
|
expect(response).toBeDefined();
|
||||||
|
expect(response.id).toBeDefined();
|
||||||
|
expect(response.id).not.toBeNull();
|
||||||
|
expect(response.id).not.toBe('');
|
||||||
|
})
|
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"types": ["jest"]
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user