Skip to content

Commit d0b7108

Browse files
committed
IStorage Refactoring
1 parent 67a8913 commit d0b7108

18 files changed

+287
-321
lines changed

src/configuration/Configuration.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import { IEnvironmentInfoCollector } from '../services/IEnvironmentInfoCollector
1717
import { IErrorParser } from '../services/IErrorParser';
1818
import { IModuleCollector } from '../services/IModuleCollector';
1919
import { IRequestInfoCollector } from '../services/IRequestInfoCollector';
20-
import { IStorage } from '../storage/IStorage';
21-
import { InMemoryStorage } from '../storage/InMemoryStorage';
20+
import { IStorageProvider } from '../storage/IStorageProvider';
21+
import { InMemoryStorageProvider } from '../storage/InMemoryStorageProvider';
2222
import { ISubmissionAdapter } from '../submission/ISubmissionAdapter';
2323
import { ISubmissionClient } from '../submission/ISubmissionClient';
2424
import { DefaultSubmissionClient } from '../submission/DefaultSubmissionClient';
@@ -76,7 +76,7 @@ export class Configuration implements IConfigurationSettings {
7676
*/
7777
public settings: Object = {};
7878

79-
public storage: IStorage;
79+
public storage: IStorageProvider;
8080

8181
public queue: IEventQueue;
8282

@@ -106,7 +106,7 @@ export class Configuration implements IConfigurationSettings {
106106
this.submissionBatchSize = inject(configSettings.submissionBatchSize) || 50;
107107
this.submissionAdapter = inject(configSettings.submissionAdapter);
108108
this.submissionClient = inject(configSettings.submissionClient) || new DefaultSubmissionClient();
109-
this.storage = inject(configSettings.storage) || new InMemoryStorage();
109+
this.storage = inject(configSettings.storage) || new InMemoryStorageProvider();
110110
this.queue = inject(configSettings.queue) || new DefaultEventQueue(this);
111111

112112
SettingsManager.applySavedServerSettings(this);

src/configuration/IConfigurationSettings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { IEnvironmentInfoCollector } from '../services/IEnvironmentInfoCollector
55
import { IErrorParser } from '../services/IErrorParser';
66
import { IModuleCollector } from '../services/IModuleCollector';
77
import { IRequestInfoCollector } from '../services/IRequestInfoCollector';
8-
import { IStorage } from '../storage/IStorage';
8+
import { IStorageProvider } from '../storage/IStorageProvider';
99
import { ISubmissionAdapter } from '../submission/ISubmissionAdapter';
1010
import { ISubmissionClient } from '../submission/ISubmissionClient';
1111

@@ -21,6 +21,6 @@ export interface IConfigurationSettings {
2121
submissionBatchSize?: number;
2222
submissionClient?: ISubmissionClient;
2323
submissionAdapter?: ISubmissionAdapter;
24-
storage?: IStorage;
24+
storage?: IStorageProvider;
2525
queue?: IEventQueue;
2626
}

src/configuration/SettingsManager.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ import { Configuration } from './Configuration';
22
import { SettingsResponse } from '../submission/SettingsResponse';
33
import { Utils } from '../Utils';
44

5-
export class SettingsManager {
6-
/**
7-
* The configuration settings path.
8-
* @type {string}
9-
* @private
10-
*/
11-
private static _configPath: string = 'ex-server-settings.json';
5+
interface ISettingsWithVersion {
6+
version: number;
7+
settings: { [key: string]: string };
8+
}
129

10+
export class SettingsManager {
1311
/**
1412
* A list of handlers that will be fired when the settings change.
1513
* @type {Array}
@@ -22,16 +20,18 @@ export class SettingsManager {
2220
}
2321

2422
public static applySavedServerSettings(config: Configuration): void {
23+
let savedSettings = this.getSavedServerSettings(config);
2524
config.log.info('Applying saved settings.');
26-
config.settings = Utils.merge(config.settings, this.getSavedServerSettings(config));
25+
config.settings = Utils.merge(config.settings, savedSettings.settings);
2726
this.changed(config);
2827
}
2928

3029
public static checkVersion(version: number, config: Configuration): void {
3130
if (version) {
32-
let savedConfigVersion = parseInt(<string>config.storage.get(`${this._configPath}-version`), 10);
33-
if (isNaN(savedConfigVersion) || version > savedConfigVersion) {
34-
config.log.info(`Updating settings from v${(!isNaN(savedConfigVersion) ? savedConfigVersion : 0)} to v${version}`);
31+
let savedSettings = this.getSavedServerSettings(config);
32+
let savedVersion = savedSettings.version;
33+
if (version > savedVersion) {
34+
config.log.info(`Updating settings from v${savedVersion} to v${version}`);
3535
this.updateSettings(config);
3636
}
3737
}
@@ -61,9 +61,12 @@ export class SettingsManager {
6161
delete config.settings[key];
6262
}
6363

64-
let path = SettingsManager._configPath; // optimization for minifier.
65-
config.storage.save(`${path}-version`, response.settingsVersion);
66-
config.storage.save(path, response.settings);
64+
let newSettings = <ISettingsWithVersion>{
65+
version: response.settingsVersion,
66+
settings: response.settings
67+
};
68+
69+
config.storage.settings.save(newSettings);
6770

6871
config.log.info('Updated settings');
6972
this.changed(config);
@@ -77,7 +80,12 @@ export class SettingsManager {
7780
}
7881
}
7982

80-
private static getSavedServerSettings(config: Configuration): Object {
81-
return config.storage.get(this._configPath) || {};
83+
private static getSavedServerSettings(config: Configuration): ISettingsWithVersion {
84+
let item = config.storage.settings.get()[0];
85+
if (item && item.value && item.value.version && item.value.settings) {
86+
return item.value;
87+
}
88+
89+
return { version: 0, settings: {} };
8290
}
8391
}

src/exceptionless.node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { NodeErrorParser } from './services/NodeErrorParser';
55
import { NodeModuleCollector } from './services/NodeModuleCollector';
66
import { NodeRequestInfoCollector } from './services/NodeRequestInfoCollector';
77
import { NodeSubmissionAdapter } from './submission/NodeSubmissionAdapter';
8-
import { NodeFileStorage } from './storage/NodeFileStorage';
8+
import { NodeFileStorageProvider } from './storage/NodeFileStorageProvider';
99
import { ExceptionlessClient } from './ExceptionlessClient';
1010

1111
const EXIT: string = 'exit';
@@ -21,7 +21,7 @@ defaults.requestInfoCollector = new NodeRequestInfoCollector();
2121
defaults.submissionAdapter = new NodeSubmissionAdapter();
2222

2323
Configuration.prototype.useLocalStorage = function() {
24-
this.storage = new NodeFileStorage('.exceptionless');
24+
this.storage = new NodeFileStorageProvider();
2525
SettingsManager.applySavedServerSettings(this);
2626
};
2727

src/exceptionless.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { DefaultModuleCollector } from './services/DefaultModuleCollector';
66
import { DefaultRequestInfoCollector } from './services/DefaultRequestInfoCollector';
77
import { DefaultSubmissionAdapter } from './submission/DefaultSubmissionAdapter';
88
import { BrowserStorage } from './storage/BrowserStorage';
9+
import { BrowserStorageProvider } from './storage/BrowserStorageProvider';
910
import { ExceptionlessClient } from './ExceptionlessClient';
1011
import { Utils } from './Utils';
1112

@@ -48,7 +49,7 @@ function processJQueryAjaxError(event, xhr, settings, error:string): void {
4849

4950
Configuration.prototype.useLocalStorage = function() {
5051
if (BrowserStorage.isAvailable()) {
51-
this.storage = new BrowserStorage();
52+
this.storage = new BrowserStorageProvider();
5253
SettingsManager.applySavedServerSettings(this);
5354
}
5455
};

src/queue/DefaultEventQueue-spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,26 @@ describe('DefaultEventQueue', () => {
2222
serverUrl: 'http://localhost:50000'
2323
});
2424

25-
expect(result.storage.getList().length).to.equal(0);
25+
expect(result.storage.queue.get().length).to.equal(0);
2626
return result;
2727
}
2828

2929
it('should enqueue event', () => {
3030
let event: IEvent = { type: 'log', reference_id: '123454321' };
3131
config.queue.enqueue(event);
32-
expect(config.storage.getList().length).to.equal(1);
32+
expect(config.storage.queue.get().length).to.equal(1);
3333
});
3434

3535
it('should process queue', () => {
3636
let event: IEvent = { type: 'log', reference_id: '123454321' };
3737
config.queue.enqueue(event);
38-
expect(config.storage.getList().length).to.equal(1);
38+
expect(config.storage.queue.get().length).to.equal(1);
3939
config.queue.process();
4040

4141
if (!(<any>config.queue)._suspendProcessingUntil) {
42-
expect(config.storage.getList().length).to.equal(0);
42+
expect(config.storage.queue.get().length).to.equal(0);
4343
} else {
44-
expect(config.storage.getList().length).to.equal(1);
44+
expect(config.storage.queue.get().length).to.equal(1);
4545
}
4646
});
4747

@@ -50,21 +50,21 @@ describe('DefaultEventQueue', () => {
5050

5151
let event: IEvent = { type: 'log', reference_id: '123454321' };
5252
config.queue.enqueue(event);
53-
expect(config.storage.getList().length).to.equal(0);
53+
expect(config.storage.queue.get().length).to.equal(0);
5454
});
5555

5656
it('should suspend processing', (done) => {
5757
config.queue.suspendProcessing(.0001);
5858

5959
let event: IEvent = { type: 'log', reference_id: '123454321' };
6060
config.queue.enqueue(event);
61-
expect(config.storage.getList().length).to.equal(1);
61+
expect(config.storage.queue.get().length).to.equal(1);
6262

6363
setTimeout(() => {
6464
if (!(<any>config.queue)._suspendProcessingUntil) {
65-
expect(config.storage.getList().length).to.equal(0);
65+
expect(config.storage.queue.get().length).to.equal(0);
6666
} else {
67-
expect(config.storage.getList().length).to.equal(1);
67+
expect(config.storage.queue.get().length).to.equal(1);
6868
}
6969

7070
done();

src/queue/DefaultEventQueue.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ILog } from '../logging/ILog';
33
import { SubmissionResponse } from '../submission/SubmissionResponse';
44
import { IEvent } from '../models/IEvent';
55
import { IEventQueue } from '../queue/IEventQueue';
6-
import { Utils } from '../Utils';
6+
import { IStorageItem } from '../storage/IStorageItem';
77

88
export class DefaultEventQueue implements IEventQueue {
99
/**
@@ -54,21 +54,16 @@ export class DefaultEventQueue implements IEventQueue {
5454
return;
5555
}
5656

57-
let key = `ex-q-${new Date().toJSON()}-${Utils.randomNumber()}`;
58-
config.log.info(`Enqueuing event: ${key} type=${event.type} ${!!event.reference_id ? 'refid=' + event.reference_id : ''}`);
59-
config.storage.save(key, event);
57+
let timestamp = config.storage.queue.save(event);
58+
let logText = `type=${event.type} ${!!event.reference_id ? 'refid=' + event.reference_id : ''}`;
59+
if (timestamp) {
60+
config.log.info(`Enqueuing event: ${timestamp} ${logText}`);
61+
} else {
62+
config.log.error(`Could not enqueue event ${logText}`);
63+
}
6064
}
6165

6266
public process(isAppExiting?: boolean): void {
63-
function getEvents(events: { path: string, value: IEvent }[]): IEvent[] {
64-
let items: IEvent[] = [];
65-
for (let index = 0; index < events.length; index++) {
66-
items.push(events[index].value);
67-
}
68-
69-
return items;
70-
}
71-
7267
const queueNotProcessed: string = 'The queue will not be processed.'; // optimization for minifier.
7368
let config: Configuration = this._config; // Optimization for minifier.
7469
let log: ILog = config.log; // Optimization for minifier.
@@ -93,14 +88,14 @@ export class DefaultEventQueue implements IEventQueue {
9388
this._processingQueue = true;
9489

9590
try {
96-
let events = config.storage.getList('ex-q', config.submissionBatchSize);
91+
let events = config.storage.queue.get(config.submissionBatchSize);
9792
if (!events || events.length === 0) {
9893
this._processingQueue = false;
9994
return;
10095
}
10196

10297
log.info(`Sending ${events.length} events to ${config.serverUrl}.`);
103-
config.submissionClient.postEvents(getEvents(events), config, (response: SubmissionResponse) => {
98+
config.submissionClient.postEvents(events.map(e => e.value), config, (response: SubmissionResponse) => {
10499
this.processSubmissionResponse(response, events);
105100
log.info('Finished processing queue.');
106101
this._processingQueue = false;
@@ -128,7 +123,7 @@ export class DefaultEventQueue implements IEventQueue {
128123

129124
if (clearQueue) {
130125
// Account is over the limit and we want to ensure that the sample size being sent in will contain newer errors.
131-
this.removeEvents(config.storage.getList('ex-q'));
126+
config.storage.queue.clear();
132127
}
133128
}
134129

@@ -152,7 +147,7 @@ export class DefaultEventQueue implements IEventQueue {
152147
}
153148
}
154149

155-
private processSubmissionResponse(response: SubmissionResponse, events: { path: string, value: IEvent }[]): void {
150+
private processSubmissionResponse(response: SubmissionResponse, events: IStorageItem[]): void {
156151
const noSubmission: string = 'The event will not be submitted.'; // Optimization for minifier.
157152
let config: Configuration = this._config; // Optimization for minifier.
158153
let log: ILog = config.log; // Optimization for minifier.
@@ -212,9 +207,9 @@ export class DefaultEventQueue implements IEventQueue {
212207
}
213208
}
214209

215-
private removeEvents(events: { path: string, value: IEvent }[]) {
210+
private removeEvents(events: IStorageItem[]) {
216211
for (let index = 0; index < (events || []).length; index++) {
217-
this._config.storage.remove(events[index].path);
212+
this._config.storage.queue.remove(events[index].timestamp);
218213
}
219214
}
220215
}

src/storage/BrowserStorage.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ export class BrowserStorage extends KeyValueStorageBase {
1515
}
1616
}
1717

18-
constructor(prefix: string = 'com.exceptionless.', maxItems: number = 20, fs?: any) {
18+
constructor(namespace: string, prefix: string = 'com.exceptionless.', maxItems: number = 20) {
1919
super(maxItems);
2020

21-
this.prefix = prefix;
21+
this.prefix = prefix + namespace + '-';
2222
}
2323

2424
write(key: string, value: string) {
@@ -29,27 +29,20 @@ export class BrowserStorage extends KeyValueStorageBase {
2929
return window.localStorage.getItem(key);
3030
}
3131

32-
readDate(key: string) {
33-
return Date.now();
32+
readAllKeys() {
33+
return Object.keys(window.localStorage)
34+
.filter(key => key.indexOf(this.prefix) === 0);
3435
}
3536

3637
delete(key: string) {
3738
window.localStorage.removeItem(key);
3839
}
3940

40-
getEntries() {
41-
let regex = new RegExp('^' + regExEscape(this.prefix));
42-
let files = Object.keys(window.localStorage)
43-
.filter(f => regex.test(f))
44-
.map(f => f.substr(this.prefix.length));
45-
return files;
41+
getKey(timestamp) {
42+
return this.prefix + timestamp;
4643
}
4744

48-
getKey(entry) {
49-
return this.prefix + super.getKey(entry);
45+
getTimestamp(key) {
46+
return parseInt(key.substr(this.prefix.length), 10);
5047
}
5148
}
52-
53-
function regExEscape(value) {
54-
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
55-
}

src/storage/BrowserStorageProvider.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { IStorage } from './IStorage';
2+
import { IStorageProvider } from './IStorageProvider';
3+
4+
import { BrowserStorage } from './BrowserStorage';
5+
6+
export class BrowserStorageProvider implements IStorageProvider {
7+
8+
queue: IStorage;
9+
settings: IStorage;
10+
11+
constructor(prefix?: string, maxQueueItems: number = 250) {
12+
this.queue = new BrowserStorage('q', prefix, maxQueueItems);
13+
this.settings = new BrowserStorage('settings', prefix, 1);
14+
}
15+
16+
}

src/storage/IStorage.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { IStorageItem } from './IStorageItem';
22

33
export interface IStorage {
4-
save(path: string, value: any): boolean;
5-
get(path: string): any;
6-
getList(searchPattern?: string, limit?: number): IStorageItem[];
7-
remove(path: string): void;
4+
save(value: any): number;
5+
get(limit?: number): IStorageItem[];
6+
remove(timestamp: number): void;
7+
clear(): void;
88
}

src/storage/IStorageItem.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export interface IStorageItem {
2-
created: number;
3-
path: string;
2+
timestamp: number;
43
value: any;
54
}

src/storage/IStorageProvider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { IStorage } from './IStorage';
2+
3+
export interface IStorageProvider {
4+
queue: IStorage;
5+
settings: IStorage;
6+
}

0 commit comments

Comments
 (0)