[ADF-1723] LogService configuration (#2496)

* log levels implementation

* documentation and test

* remove logservieMock

* add logLevel in app config file

* remove semicolons

* fix pagination test

* fix test form

* silent test in production config

* fix test
This commit is contained in:
Eugenio Romano
2017-10-19 12:54:56 +01:00
committed by Denys Vuika
parent de8fa02ef7
commit 8b0047337f
19 changed files with 350 additions and 79 deletions

View File

@@ -56,6 +56,7 @@
"files": {
"excluded": [".DS_Store", "desktop.ini", ".git"]
},
"logLevel" : "trace",
"activiti": {
"rest": {
"fields": [

View File

@@ -56,6 +56,7 @@
"files": {
"excluded": [".DS_Store", "desktop.ini", ".git"]
},
"logLevel" : "silent",
"activiti": {
"rest": {
"fields": [

View File

@@ -369,7 +369,7 @@ for more information about installing and using the source code.
- [*Discovery api service](../ng2-components/ng2-alfresco-core/src/services/discovery-api.service.ts)
- [*Favorites api service](../ng2-components/ng2-alfresco-core/src/services/favorites-api.service.ts)
- [*Highlight transform service](../ng2-components/ng2-alfresco-core/src/services/highlight-transform.service.ts)
- [*Log service](../ng2-components/ng2-alfresco-core/src/services/log.service.ts)
- [Log service](log.service.md)
- [*Nodes api service](../ng2-components/ng2-alfresco-core/src/services/nodes-api.service.ts)
- [*Page title service](../ng2-components/ng2-alfresco-core/src/services/page-title.service.ts)
- [*People content service](../ng2-components/ng2-alfresco-core/src/services/people-content.service.ts)

63
docs/log.service.md Normal file
View File

@@ -0,0 +1,63 @@
# Log Service
Provide a log functionality for your ADF application.
<!-- markdown-toc start - Don't edit this section. npm run toc to generate it-->
<!-- toc -->
- [Basic Usage](#basic-usage)
* [Log levels](#log-levels)
<!-- tocstop -->
<!-- markdown-toc end -->
## Basic Usage
**app.component.ts**
```ts
import { LogService } from 'ng2-alfresco-core';
@Component({...})
export class AppComponent {
constructor(logService: LogService) {
}
myMethod(){
this.logService.error('My error');
this.logService.trace('My trace')
this.logService.debug('My debug')
this.logService.info('My info')
this.logService.warn('My warn')
}
}
```
### Log levels
The log service provide 6 level of logs:
Name | Level
-|-
TRACE |5
DEBUG |4
INFO |3
WARN |2
ERROR |1
SILENT |0
You can configure the log level setting the ***logLevel*** properties in the **app.config.json**. By default the level is TRACE.
If you want set for example the log to warning:
**app.config.json**
```json
{
"logLevel": "WARN"
}
```

View File

@@ -34,7 +34,7 @@ describe('FormComponent', () => {
let logService: LogService;
beforeEach(() => {
logService = new LogService();
logService = new LogService(null);
visibilityService = new WidgetVisibilityService(null, logService);
spyOn(visibilityService, 'refreshVisibility').and.stub();
formService = new FormService(null, null, logService);

View File

@@ -17,7 +17,6 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreModule, LogService } from 'ng2-alfresco-core';
import { LogServiceMock } from 'ng2-alfresco-core';
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
import { MaterialModule } from '../../material.module';
@@ -94,7 +93,7 @@ describe('DynamicTableWidgetComponent', () => {
TextEditorComponent, ErrorWidgetComponent],
providers: [
FormService,
{provide: LogService, useClass: LogServiceMock},
LogService,
ActivitiAlfrescoContentService,
EcmModelService,
WidgetVisibilityService
@@ -285,7 +284,6 @@ describe('DynamicTableWidgetComponent', () => {
widget.onSaveChanges();
expect(widget.editMode).toBeFalsy();
expect(logService.error).toHaveBeenCalledWith(widget.ERROR_MODEL_NOT_FOUND);
});
it('should cancel changes', () => {

View File

@@ -16,7 +16,7 @@
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreModule, LogServiceMock } from 'ng2-alfresco-core';
import { CoreModule } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { EcmModelService } from '../../../services/ecm-model.service';
@@ -36,13 +36,11 @@ describe('RadioButtonsWidgetComponent', () => {
let formService: FormService;
let widget: RadioButtonsWidgetComponent;
let visibilityService: WidgetVisibilityService;
let logService: LogServiceMock;
beforeEach(() => {
logService = new LogServiceMock();
formService = new FormService(null, null, logService);
visibilityService = new WidgetVisibilityService(null, logService);
widget = new RadioButtonsWidgetComponent(formService, visibilityService, logService);
formService = new FormService(null, null, null);
visibilityService = new WidgetVisibilityService(null, null);
widget = new RadioButtonsWidgetComponent(formService, visibilityService, null);
widget.field = new FormFieldModel(new FormModel(), { restUrl: '<url>' });
});
@@ -122,12 +120,6 @@ describe('RadioButtonsWidgetComponent', () => {
expect(formService.getRestFieldValues).toHaveBeenCalled();
});
it('should log error to console by default', () => {
spyOn(logService, 'error').and.stub();
widget.handleError('Err');
expect(logService.error).toHaveBeenCalledWith('Err');
});
xit('should update the field value when an option is selected', () => {
spyOn(widget, 'checkVisibility').and.stub();
widget.onOptionClick('fake-opt');

View File

@@ -17,7 +17,7 @@
import { OverlayContainer } from '@angular/cdk/overlay';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreModule, LogServiceMock } from 'ng2-alfresco-core';
import { CoreModule } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { By } from '@angular/platform-browser';
@@ -37,14 +37,12 @@ describe('TypeaheadWidgetComponent', () => {
let formService: FormService;
let widget: TypeaheadWidgetComponent;
let visibilityService: WidgetVisibilityService;
let logService: LogServiceMock;
let overlayContainerElement: HTMLElement;
beforeEach(() => {
logService = new LogServiceMock();
formService = new FormService(null, null, logService);
visibilityService = new WidgetVisibilityService(null, logService);
widget = new TypeaheadWidgetComponent(formService, visibilityService, logService);
formService = new FormService(null, null, null);
visibilityService = new WidgetVisibilityService(null, null);
widget = new TypeaheadWidgetComponent(formService, visibilityService, null);
widget.field = new FormFieldModel(new FormModel({ taskId: 'task-id' }));
});

View File

@@ -16,7 +16,7 @@
*/
import { SimpleChange } from '@angular/core';
import { AppsProcessService, LogServiceMock } from 'ng2-alfresco-core';
import { AppsProcessService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { FilterProcessRepresentationModel } from '../models/filter-process.model';
import { ProcessService } from '../services/process.service';
@@ -27,7 +27,6 @@ describe('ActivitiFilters', () => {
let filterList: ProcessFiltersComponent;
let processService: ProcessService;
let appsProcessService: AppsProcessService;
let logService: LogServiceMock;
let fakeGlobalFilter = [];
fakeGlobalFilter.push(new FilterProcessRepresentationModel({
@@ -57,9 +56,8 @@ describe('ActivitiFilters', () => {
});
beforeEach(() => {
logService = new LogServiceMock();
processService = new ProcessService(null, logService);
appsProcessService = new AppsProcessService(null, logService);
processService = new ProcessService(null, null);
appsProcessService = new AppsProcessService(null, null);
filterList = new ProcessFiltersComponent(processService, appsProcessService);
});

View File

@@ -42,7 +42,6 @@ import { AuthenticationService } from './src/services/authentication.service';
import { CommentProcessService } from './src/services/comment-process.service';
import { ContentService } from './src/services/content.service';
import { CookieService } from './src/services/cookie.service';
import { LogServiceMock } from './src/services/log.service';
import { LogService } from './src/services/log.service';
import { NotificationService } from './src/services/notification.service';
import { PageTitleService } from './src/services/page-title.service';
@@ -90,7 +89,6 @@ export { AuthGuardEcm } from './src/services/auth-guard-ecm.service';
export { AuthGuardBpm } from './src/services/auth-guard-bpm.service';
export { NotificationService } from './src/services/notification.service';
export { LogService } from './src/services/log.service';
export { LogServiceMock } from './src/services/log.service';
export { AuthenticationService } from './src/services/authentication.service';
export { TranslationService, TRANSLATION_PROVIDER, TranslationProvider } from './src/services/translation.service';
export { AlfrescoTranslateLoader } from './src/services/translate-loader.service';
@@ -185,7 +183,6 @@ export function providers() {
UserPreferencesService,
NotificationService,
LogService,
LogServiceMock,
AuthenticationService,
AlfrescoContentService,
AlfrescoSettingsService,

View File

@@ -20,6 +20,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpModule } from '@angular/http';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MaterialModule } from '../../material.module';
import { AppConfigService } from '../../services/app-config.service';
import { LogService } from '../../services/log.service';
import { AlfrescoTranslateLoader } from '../../services/translate-loader.service';
import { TranslationService } from '../../services/translation.service';
@@ -69,7 +70,8 @@ describe('PaginationComponent', () => {
],
providers: [
TranslationService,
LogService
LogService,
AppConfigService
],
schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents()

View File

@@ -24,6 +24,7 @@ import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { CardViewMapItemModel } from '../../models/card-view-mapitem.model';
import { AppConfigService } from '../../services/app-config.service';
import { CardViewUpdateService } from '../../services/card-view-update.service';
import { LogService } from '../../services/log.service';
import { AlfrescoTranslateLoader } from '../../services/translate-loader.service';
@@ -59,6 +60,7 @@ describe('CardViewMapItemComponent', () => {
CardViewMapItemComponent
],
providers: [
AppConfigService,
CardViewUpdateService,
LogService
]

View File

@@ -23,6 +23,7 @@ import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { CardViewTextItemModel } from '../../models/card-view-textitem.model';
import { AppConfigService } from '../../services/app-config.service';
import { CardViewUpdateService } from '../../services/card-view-update.service';
import { LogService } from '../../services/log.service';
import { AlfrescoTranslateLoader } from '../../services/translate-loader.service';
@@ -55,6 +56,7 @@ describe('CardViewTextItemComponent', () => {
CardViewTextItemComponent
],
providers: [
AppConfigService,
CardViewUpdateService,
LogService
]

View File

@@ -0,0 +1,33 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export class LogLevelsEnum extends Number {
static TRACE: number = 5;
static DEBUG: number = 4;
static INFO: number = 3;
static WARN: number = 2;
static ERROR: number = 1;
static SILENT: number = 0;
}
export let logLevels: any[] = [
{level: LogLevelsEnum.TRACE, name: 'TRACE'},
{level: LogLevelsEnum.DEBUG, name: 'DEBUG'},
{level: LogLevelsEnum.INFO, name: 'INFO'},
{level: LogLevelsEnum.ERROR, name: 'ERROR'},
{level: LogLevelsEnum.SILENT, name: 'SILENT'}
];

View File

@@ -0,0 +1,112 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpModule } from '@angular/http';
import { AppConfigService } from './app-config.service';
import { LogService } from './log.service';
describe('Log Service', () => {
let providesLogComponent: ComponentFixture<ProvidesLogComponent>;
let appConfigService: AppConfigService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpModule
],
declarations: [ProvidesLogComponent],
providers: [
LogService,
AppConfigService
]
});
TestBed.compileComponents();
}));
beforeEach(() => {
appConfigService = TestBed.get(AppConfigService);
});
it('should log all the levels by default', () => {
providesLogComponent = TestBed.createComponent(ProvidesLogComponent);
spyOn(console, 'log');
spyOn(console, 'error');
spyOn(console, 'trace');
providesLogComponent.componentInstance.log();
providesLogComponent.componentInstance.error();
providesLogComponent.componentInstance.trace();
expect(console.log).toHaveBeenCalled();
expect(console.error).toHaveBeenCalled();
expect(console.trace).toHaveBeenCalled();
});
it('should not log anything if is silent', () => {
appConfigService.config['logLevel'] = 'silent';
providesLogComponent = TestBed.createComponent(ProvidesLogComponent);
spyOn(console, 'log');
spyOn(console, 'error');
spyOn(console, 'trace');
providesLogComponent.componentInstance.log();
providesLogComponent.componentInstance.error();
providesLogComponent.componentInstance.trace();
expect(console.log).not.toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalled();
expect(console.trace).not.toHaveBeenCalled();
});
});
@Component({
template: '',
providers: [LogService]
})
class ProvidesLogComponent {
constructor(public logService: LogService) {
}
error() {
this.logService.error('Test message');
}
info() {
this.logService.info('Test message');
}
warn() {
this.logService.warn('Test message');
}
log() {
this.logService.log('Test message');
}
trace() {
this.logService.trace('Test message');
}
}

View File

@@ -16,48 +16,97 @@
*/
import { Injectable } from '@angular/core';
import { logLevels, LogLevelsEnum } from '../models/log-levels.model';
import { AppConfigService } from './app-config.service';
@Injectable()
export class LogService {
get assert(): (message?: any, ...optionalParams: any[]) => void {
return console.assert.bind(console);
currentLogLevel: LogLevelsEnum = LogLevelsEnum.TRACE;
constructor(appConfig: AppConfigService) {
if (appConfig) {
let configLevel: string = appConfig.get<string>('logLevel');
if (configLevel) {
this.currentLogLevel = this.getCurrentLogLevel(configLevel);
}
}
}
get error(): (message?: any, ...optionalParams: any[]) => void {
return console.error.bind(console);
get error(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel >= LogLevelsEnum.ERROR) {
return console.error.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
get group(): (message?: any, ...optionalParams: any[]) => void {
return console.group.bind(console);
get info(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel >= LogLevelsEnum.INFO) {
return console.info.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
get groupEnd(): (message?: any, ...optionalParams: any[]) => void {
return console.groupEnd.bind(console);
get log(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel >= LogLevelsEnum.TRACE) {
return console.log.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
get info(): (message?: any, ...optionalParams: any[]) => void {
return console.info.bind(console);
get trace(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel >= LogLevelsEnum.TRACE) {
return console.trace.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
get log(): (message?: any, ...optionalParams: any[]) => void {
return console.log.bind(console);
get warn(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel >= LogLevelsEnum.WARN) {
return console.warn.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
get warn(): (message?: any, ...optionalParams: any[]) => void {
return console.warn.bind(console);
get assert(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel !== LogLevelsEnum.SILENT) {
return console.assert.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
}
export class LogServiceMock {
assert(message?: any, ...optionalParams: any[]) {}
error(message?: any, ...optionalParams: any[]) {}
group(message?: any, ...optionalParams: any[]) {}
groupEnd(message?: any, ...optionalParams: any[]) {}
info(message?: any, ...optionalParams: any[]) {}
log(message?: any, ...optionalParams: any[]) {}
warn(message?: any, ...optionalParams: any[]) {}
get group(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel !== LogLevelsEnum.SILENT) {
return console.group.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
get groupEnd(): (message?: any, ...optionalParams: any[]) => any {
if (this.currentLogLevel !== LogLevelsEnum.SILENT) {
return console.groupEnd.bind(console);
}
return (message?: any, ...optionalParams: any[]) => {
};
}
getCurrentLogLevel(level: string): LogLevelsEnum {
return logLevels.find((currentLevel: any) => {
return currentLevel.name.toLocaleLowerCase() === level.toLocaleLowerCase();
});
}
}

View File

@@ -16,7 +16,7 @@
*/
import { async, TestBed } from '@angular/core/testing';
import { CookieService, CoreModule, LogService, LogServiceMock } from 'ng2-alfresco-core';
import { CookieService, CoreModule, LogService } from 'ng2-alfresco-core';
import { CookieServiceMock } from '../../../ng2-alfresco-core/src/assets/cookie.service.mock';
import { DocumentListService } from './document-list.service';
@@ -95,7 +95,7 @@ describe('DocumentListService', () => {
providers: [
DocumentListService,
{ provide: CookieService, useClass: CookieServiceMock },
{ provide: LogService, useClass: LogServiceMock }
LogService
]
}).compileComponents();
}));

View File

@@ -17,7 +17,7 @@
import { DebugElement } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AlfrescoTranslationService, CoreModule, FileModel, LogService, LogServiceMock, UploadService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, CoreModule, FileModel, LogService, UploadService } from 'ng2-alfresco-core';
import { TranslationMock } from '../assets/translation.service.mock';
import { FileDraggableDirective } from '../directives/file-draggable.directive';
@@ -77,7 +77,7 @@ describe('UploadDragAreaComponent', () => {
providers: [
UploadService,
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
{ provide: LogService, useClass: LogServiceMock }
LogService
]
}).compileComponents();
}));

View File

@@ -34,10 +34,33 @@
"bugs": {
"url": "https://github.com/Alfresco/alfresco-ng2-components/issues"
},
"keywords": [
"alfresco",
"angular"
],
"contributors": {
"0": {
"name": "Eugenio Romano",
"email": "eugenio.romano@alfresco.com"
},
"1": {
"name": "Eugenio Romano",
"email": "eugenio.romano@alfresco.com"
},
"2": {
"name": "Denys Vuika",
"email": "denys.vuika@gmail.com"
},
"3": {
"name": "Eugenio Romano",
"email": "eugenio.romano@alfresco.com"
}
},
"keywords": {
"0": "alfresco-ng2-components",
"1": "angular2",
"2": "typescript",
"3": "alfresco",
"4": "activiti",
"5": "ecm",
"6": "bpm"
},
"dependencies": {
"@angular/animations": "4.4.5",
"@angular/cdk": "2.0.0-beta.12",
@@ -45,7 +68,6 @@
"@angular/compiler": "4.4.5",
"@angular/compiler-cli": "4.4.5",
"@angular/core": "4.4.5",
"@angular/flex-layout": "2.0.0-beta.9",
"@angular/forms": "4.4.5",
"@angular/http": "4.4.5",
"@angular/material": "2.0.0-beta.12",
@@ -54,24 +76,25 @@
"@angular/router": "4.4.5",
"@ngx-translate/core": "7.0.0",
"alfresco-js-api": "1.9.0",
"chart.js": "2.5.0",
"core-js": "2.4.1",
"hammerjs": "2.0.8",
"minimatch": "3.0.4",
"moment": "2.15.1",
"ng2-activiti-diagrams": "1.9.0",
"ng2-activiti-form": "1.9.0",
"ng2-activiti-tasklist": "1.9.0",
"ng2-alfresco-core": "1.9.0",
"ng2-alfresco-datatable": "1.9.0",
"ng2-alfresco-documentlist": "1.9.0",
"ng2-charts": "1.6.0",
"pdfjs-dist": "1.5.404",
"raphael": "2.2.7",
"reflect-metadata": "0.1.10",
"rxjs": "5.1.0",
"systemjs": "0.19.27",
"zone.js": "0.8.12"
"zone.js": "0.8.12",
"ng2-alfresco-core": "1.9.0",
"raphael": "2.2.7",
"chart.js": "2.5.0",
"ng2-activiti-diagrams": "1.9.0",
"ng2-charts": "1.6.0",
"@angular/flex-layout": "2.0.0-beta.9",
"ng2-activiti-form": "1.9.0",
"ng2-alfresco-datatable": "1.9.0",
"ng2-activiti-tasklist": "1.9.0",
"ng2-alfresco-documentlist": "1.9.0",
"minimatch": "3.0.4",
"pdfjs-dist": "1.5.404"
},
"devDependencies": {
"@types/hammerjs": "2.0.35",