have a problem with implementing custom logger by extending default logger in NestJS. I followed documentation https://docs.nestjs.com/techniques/logger#using-the-logger-for-application-logging.
import { Injectable, Logger, Scope } from '#nestjs/common';
#Injectable({ scope: Scope.TRANSIENT })
export class LoggerService extends Logger {
votes = 0;
debug(message: string, trace?: string) {
super.debug(message, trace);
}
error(message: string, trace?: string) {
super.error(message, trace);
}
log(message: string, trace?: string) {
this.votes = this.votes + 1;
console.log(this.votes, 'log', message);
super.log(message, trace);
}
verbose(message: string, trace?: string) {
super.verbose(message, trace);
}
warn(message: string, trace?: string) {
super.warn(message, trace);
}
}
and in main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './shared/exception-filters/all-exception-filters';
import { LoggerService } from './shared/modules/logger/logger.service';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: false,
});
app.useLogger(new LoggerService());
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(3000);
}
bootstrap();
And in my controller
Controller('user')
export class UserController {
constructor(private readonly userService: UserService, private logger: LoggerService) {}
#Get('/logger-example')
getLoggerExample() {
this.logger.log('it works ?');
return 'loggerExample';
}
And of course user module imports logger module.
I have two problems with that logger:
First one:
When i hit user/logger-example, i got two times log from Logger. It looks like that logger from main.ts exactly app.useLogger(new LoggerService()); is executed along with injected instance, in future i want to put some async logger like pino or something and i'm afraid that log will be send two times. I assume something is wrong with my configuration, because it doesn't look like some common problem. What is more from default Logger i got properly one message.
The second one:
If i also inject that service to different module, for example payments. And made the same endpoint as for user, votes field on Logger class is always 0. Is it proper behaviour for transient scope of injection ? Because as i understood it should be injected per module. So in one module that counter shouldn't be reseted.
Is it properly configured ? Or it is normal behaviour ? I'm really afraid about two loggers executed in one this.logger.log.
I found, that all elements passed into super.log are forced to be another log line. So duplicated logs are from two arguments at super.log. Please forward only message.
log(message: string) {
this.votes = this.votes + 1;
console.log(this.votes, 'log', message);
super.log(message);
}
Related
Learning NestJs actually and facing an issue saving typeorm OneToMany relation.
Let's say I have two modules ProjectsModule # PlansModule
Exists a OneToMany relation between Plan & Project entities
#Entity()
export class Project extends BaseEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
...
#OneToMany(type => Plan, plan => plan.project, { eager: true })
plans: Plan[];
}
#Entity()
export class Plan extends BaseEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
...
#ManyToOne(type => Project, project => project.plans, { eager: false } )
project: Project;
#Column()
projectId: string;
}
In the ProjectsModule, I have a ProjectsService with this method:
async getProjectById(
id: string,
user: User
): Promise<Project> {
const found = await this.projectRepository.findOne({ where: { id, ownerId: user.id } });
if(!found) {
throw new NotFoundException(`Project with ID "${id}" not found`)
}
return found;
}
My problem is when I try to save a new Plan.
My PlansService calls the PlanRepository like that
async createPlan(
createPlanDto: CreatePlanDto,
user: User
): Promise<Plan> {
return this.planRepository.createPlan(createPlanDto, user);
}
And on the PlanRepository :
constructor(
#Inject(ProjectsService)
private projectsService: ProjectsService
) {
super();
}
async createPlan(
createPlanDto: CreatePlanDto,
user: User
): Promise<Plan> {
const { title, description, project } = createPlanDto;
const plan = new Plan();
const projectFound = await this.projectsService.getProjectById(project, user)
plan.title = title;
plan.description = description;
plan.status = PlanStatus.ENABLED;
plan.owner = user;
plan.project = project;
try {
await plan.save();
} catch (error) {
this.logger.error(`Failed to create a Plan for user "${user.email}". Data: ${JSON.stringify(createPlanDto)}`, error.stack);
throw new InternalServerErrorException();
}
delete plan.owner;
return plan;
}
Trying this throws me this error when sending a POST request to my plan controller :
TypeError: this.projectsService.getProjectById is not a function
And trying a
console.log('service', this.projectsService)
give me
service EntityManager {
repositories: [],
plainObjectToEntityTransformer: PlainObjectToNewEntityTransformer {},
connection: Connection {
I guess I'm not using the projectsService properly but I don't understand where I could have made a mistake.
On the module's side I'm exporting the ProjectsService in his module:
exports: [ProjectsService]
And importing the full ProjectsModule into the PlansModule:
imports: [
TypeOrmModule.forFeature([PlanRepository]),
AuthModule,
ProjectsModule
],
Sorry for the long post, trying to be exhaustive.
import { Injectable, NotFoundException } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { User } from '../auth/user.entity';
import { PlanRepository } from './plan.repository';
import { GetPlanFilterDto } from './dto/get-plan-filter.dto';
import { Plan } from './plan.entity';
import { CreatePlanDto } from './dto/create-plan.dto';
#Injectable()
export class PlansService {
constructor(
#InjectRepository(PlanRepository)
private planRepository: PlanRepository,
) {}
async getPlans(filterDto: GetPlanFilterDto, user: User): Promise<Plan[]> {
return this.planRepository.find({ ...filterDto, ownerId: user.id });
}
async getPlanById(id: string, user: User): Promise<Plan> {
return this.planRepository.findOne({
where: { id, ownerId: user.id },
});
}
async createPlan(createPlanDto: CreatePlanDto, user: User): Promise<Plan> {
const { project, ...data } = createPlanDto;
return this.planRepository
.create({
projectId: project,
ownerId: user.id,
...data,
})
.save();
}
}
This PlanService only uses the internal methods of the Repository, if you're logging in the event of an Error, ExceptionFilter would be a suitable option for this: https://docs.nestjs.com/exception-filters.
Instead of checking if the plan had been found, you can use an interceptor:
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
NotFoundException,
} from '#nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
#Injectable()
export class PlanNotFoundInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(plan => {
if (!plan) {
throw new NotFoundException("plan couldn't be found");
}
return plan;
}),
);
}
}
Then on your getById (Controller) use #UseInterceptor, this decouples your service, data access, logging, validation, etc..
I've simplified the implementation (for Interceptor), you may need to adjust it slightly to suit your exact need.
yarn run v1.22.4
$ jest
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
PASS src/auth/user.repository.spec.ts
PASS src/projects/projects.service.spec.ts
PASS src/auth/jwt.strategy.spec.ts
PASS src/auth/user.entity.spec.ts
Test Suites: 4 passed, 4 total
Tests: 18 passed, 18 total
Snapshots: 0 total
Time: 3.774s, estimated 4s
Ran all test suites.
Done in 4.58s.
I haven't spent much time reviewing your tests, but the changes made haven't made any breaking changes to the unit tests (can't say the same for e2e, personally don't use Cucumber.js).
The point of this answer isn't to provide you the code needed, but the abstractions you can use to solve the tightly coupled components.
You can also use the Interceptor to validate the request, check if a project is present, check if it exists, if not abort with error. Again decoupling your error handling from your controller/service/whatever.
You also have the option to pluck/add things to the request, for example a .user that's authenticated, or a value from a header. (Could be useful if you want to send the projectId into the Controller via the Request object).
I tried to use the internal Logger of nestjs (described on https://docs.nestjs.com/techniques/logger -> but with no description of how to use it)
But I had problems (tried to inject LoggerService and so on)
Can anybody explain how to do this?
Best practice
Better than accessing the Logger statically is to create an instance for your class:
#Controller()
export class AppController {
private readonly logger = new Logger(AppController.name);
#Get()
async get() {
this.logger.log('Getting stuff');
}
}
Why is this better?
You can provide a context in the constructor like new Logger(AppController.name) so that the class name (or anything else) will be part of all log messages in this class.
If you at some point want to extend or replace the default LoggerService, you do not need to change any of your application code besides setting the new logger. Your new logger will automatically be used. If you access it statically it will continue to take the default implementation.
const app = await NestFactory.create(AppModule, {logger: new MyLogger()});
You can mock the Logger in your tests:
module.useLogger(new NoOpLogger());
You need to import first into your class:
import { Logger } from '#nestjs/common';
and then you can begin with logging:
Logger.log('info')
Logger.warn('warning')
Logger.error('something went wrong! ', error)
This answer might be useful for others who are trying with CustomLogger Implementation.
I am trying to show a sample custom logger implementation and how it can be injected to the Nestjs framework.
I understand that Nestjs inherently uses pino logger. This is just a custom implementation of logger service (which you can replace with bunyan, winston, etc..)
This is the folder structure I use:
> src /
> modules /
> database /
> ...
> database.module.ts
> api /
> services /
> controllers /
> interceptors /
> middlewares /
> models /
> schemas /
> shared /
> services /
> app.util.service.ts
> pino.logger.service.ts
> utils /
> interceptors /
> filters /
> main.ts
> app.controller.ts
> app.service.ts
> server.util.service.ts
This is the main gist of it. So the logger service is implemented as follows
import {Injectable, LoggerService, Scope} from "#nestjs/common";
import * as pino from 'pino';
import {AppUtilService} from "./app.util.service";
import * as os from "os";
import {APP_LOG_REDACT, APP_MESSAGE_KEY} from "../utils/app.constants";
#Injectable({
scope: Scope.DEFAULT
})
export class PinoLoggerService implements LoggerService{
constructor(private appUtilService: AppUtilService) {
}
logService = (fileNameString): pino.Logger => {
return pino({
useLevelLabels: true,
prettyPrint: this.appUtilService.isDevEnv(),
// tslint:disable-next-line: object-literal-sort-keys
messageKey: APP_MESSAGE_KEY,
level: this.appUtilService.getLogLevel(),
redact: {
paths: APP_LOG_REDACT,
censor: '**SECRET-INFO**'
},
base: {
hostName: os.hostname(),
platform: os.platform(),
processId: process.pid,
timestamp: this.appUtilService.getCurrentLocaleTimeZone(),
// tslint:disable-next-line: object-literal-sort-keys
fileName: this.appUtilService.getFileName(fileNameString),
},
});
}
debug(message: any, context?: string): any {
}
error(message: any, trace?: string, context?: string): any {
}
log(message: any, context?: string): any {
}
warn(message: any, context?: string): any {
}
}
The custom implementation is implemented with the my specific options in pinojs github
I am using fastifyjs instead of express (again to match my prject needs). So I've added the logger in fastify js server options. If you are using express, its better to specify the new custom implementation in the Nest application Adapter as stated above.
My util service that takes care of implementing the fastify server
import * as fastify from "fastify";
import {Http2Server, Http2ServerRequest, Http2ServerResponse} from "http2";
import {DocumentBuilder, SwaggerModule} from "#nestjs/swagger";
import * as fs from "fs";
import * as path from "path";
import * as uuid from "uuid";
import * as qs from "query-string";
import {PinoLoggerService} from "./modules/shared/services/pino.logger.service";
import {AppUtilService} from "./modules/shared/services/app.util.service";
import {AppConstantsService} from "./modules/shared/services/app.constants.service";
import {AppModel} from "./modules/shared/model/app.model";
import {Reflector} from "#nestjs/core";
export class ServerUtilService {
private logService;
private appConstantsService;
private appUtilServiceInstance: AppUtilService;
private fastifyInstance: fastify.FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse>;
constructor() {
this.appUtilServiceInstance = new AppUtilService();
this.logService = new PinoLoggerService(this.appUtilServiceInstance);
this.appConstantsService = new AppConstantsService(this.appUtilServiceInstance);
}
retrieveAppConstants(): AppModel {
return this.appConstantsService.getServerConstants();
}
retrieveAppUtilService(): AppUtilService {
return this.appConstantsService;
}
createFastifyServerInstance = (): fastify.FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse> => {
const serverConstants = this.appConstantsService.getServerConstants();
const httpsOptions = {
cert: fs.readFileSync(path.join(process.cwd() + '/https-keys/cert.pem')),
key: fs.readFileSync(path.join(process.cwd() + '/https-keys/key.pem')),
allowHTTP1: true,
rejectUnauthorized: true,
};
this.fastifyInstance = fastify({
http2: true,
https: httpsOptions,
bodyLimit: 26214400,
pluginTimeout: 20000,
genReqId: () => {
return uuid.v4().toString();
},
requestIdHeader: serverConstants.requestIdHeader,
modifyCoreObjects: true,
trustProxy: serverConstants.trustProxy,
ignoreTrailingSlash: true,
logger: this.logService,
querystringParser: (str) => {
return qs.parse(str);
},
});
this.addContentTypeParser();
return this.fastifyInstance;
};
private addContentTypeParser() {
this.fastifyInstance.addContentTypeParser('*', (req, done) => {
let data = '';
req.on('data', chunk => {
console.log('inside data listener event');
return data += chunk; });
req.on('end', () => {
done(null,data);
})
});
}
}
export const ServerUtilServiceInstance = new ServerUtilService();
And in my main.ts
async function bootstrap() {
const fastifyServerInstance =
ServerUtilServiceInstance.createFastifyServerInstance();
const serverConstants = ServerUtilServiceInstance.retrieveAppConstants();
const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(fastifyServerInstance)
);
....
... // global filters, interceptors, pipes
....
await app.listen(serverConstants.port, '0.0.0.0');
}
Best practice is to inject the existing logger.
app.module.ts
import { Logger, Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
#Module({
imports: [],
controllers: [AppController],
providers: [AppService, Logger],
})
export class AppModule {}
And in the app.service.ts
import { Injectable, Logger } from '#nestjs/common';
#Injectable()
export class AppService {
constructor(private readonly logger: Logger) {}
sayHello() {
this.logger.log('Hello world!')
}
}
The answer is simple. There are static methods on the Logger class.
e.g.
static log(message: string, context = '', isTimeDiffEnabled = true)
Usage:
Logger.log('Only a test');
Simply you can use logger for your requirement(for error, for warn).This is the sample code for it.
import {Logger, Injectable} from '#nestjs/common';
#Injectable()
export class EmployersService {
private readonly logger = new Logger(EmployersService.name);
findAll() {
this.logger.log('info message'); //for info
this.logger.warn('warn message'); //for warn
this.logger.error('error message'); //for error
}
}
then output:
I'm new to Angular and TypeScript and just started working on a project using MEAN stack (MongoDB, Express, Angular, Node.js).
I created this mongoose module :
import * as mongoose from 'mongoose';
var Schema = mongoose.Schema;
const entrepriseSchema = new mongoose.Schema({
name: {type: String, unique: true, required : true},
telephone: Number,
logo: String,
web_site: String,
sites: [
{site_id: {type: Schema.Types.ObjectId, ref: 'Site'}}
]
});
const Entreprise = mongoose.model('Entreprise', entrepriseSchema);
export default Entreprise;
and this is my entreprise.component.ts :
import { Component, OnInit } from '#angular/core';
import { Http } from '#angular/http';
import { FormGroup, FormControl, Validators, FormBuilder } from '#angular/forms';
import { ActivatedRoute } from '#angular/router';
import { EntrepriseService } from '../services/entreprise.service';
import { SiteService } from '../services/site.service';
#Component({
selector: 'app-entreprise',
templateUrl: './entreprise.component.html',
styleUrls: ['./entreprise.component.scss'],
providers: [EntrepriseService, SiteService]
})
export class EntrepriseComponent implements OnInit {
entreprise = {};
sites = [];
id: String;
constructor(private entrepriseService: EntrepriseService,
private siteService: SiteService,
private http: Http,
private route: ActivatedRoute) {
this.id = route.snapshot.params['id'];
}
ngOnInit() {
this.getEntrepriseById(this.id);
//not working
//console.log(this.entreprise.name);
//console.log(this.entreprise.sites);
//this.getSitesIn(this.entreprise.sites);
}
getEntrepriseById(id) {
this.entrepriseService.getEntreprise(id).subscribe(
data => this.entreprise = data,
error => console.log(error)
);
}
getSitesIn(ids) {
this.siteService.getSitesIn(ids).subscribe(
data => this.sites = data,
error => console.log(error)
);
}
}
when I try to display the properties of the returned from entreprise.component.html it works fine and displays all the properties :
<h3>{{entreprise.name}}</h3>
<div *ngFor="let site of entreprise.sites">
{{site.site_id}}
</div>
{{entreprise.logo}}
{{entreprise.web_site}}
but how can I access the same properties on the TypeScript side ?
The commented code in the EntrepriseComponent is what I'm trying to accomplish but it's not working since this.entreprise is type {} .
The Enterprise model/schema that you created in Mongoose in Node.js resides on the server side. If you want the TypeScript code on the UI to recognize the properties in Enterprise, you will have to create a class in your angular codebase.
Create a folder named, say, models at the same level as your services folder. (Optional)
Create two files named site.ts and enterprise.ts in the models folder created in the previous step (You can put these file at a different location if you want) with the following contents:
site.ts
export interface Site {
site_id?: string;
}
enterprise.ts
import { Site } from './site';
export interface Enterprise {
name?: string;
telephone?: string;
logo?: string;
web_site?: string;
sites?: Site[];
}
Now, inside the EntrepriseComponent file, add the following imports
import { Enterprise} from '../models/entreprise';
import { Site } from '../models/site';
And change the first lines inside the EntrepriseComponent file to
export class EntrepriseComponent implements OnInit {
entreprise: Enterprise = {};
sites: Site[] = [];
Now, the enterprise attribute will be of type Enterprise and you will be able to access the properties that we declared in the enterprise.ts file.
Update:
Also, you cannot console.log(this.enterprise.name) immediately after this.getEntrepriseById(this.id); in your ngOnInit() function. This is because the web service you are making to get the enterprise object would not have resolved when you are trying to log it to the console.
If you want to see the enterprise object in the console or you want to run some code that needs to run after the service call has resolved and the this.enterprise object has a value, the best place to do this would be your getEntrepriseById function. Change the getEntrepriseById function to
getEntrepriseById(id) {
this.entrepriseService.getEntreprise(id).subscribe(
data => {
this.enterprise = data;
console.log(this.enterprise.name);
// Any code to run after this.enterprise resolves can go here.
},
error => console.log(error)
);
}
For some reason my services aren't working. I've been lurking SO for two days trying to find similar questions, but they don't fit my problem.
Service.ts:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { CarObject } from './make';
#Injectable()
export class EdmundsService {
private stylesurl = 'REDACTED';
constructor(private http: Http) { }
getCars(): Observable<CarObject[]> {
return this.http.get(this.stylesurl)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || { };
}
private handleError (error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}
These are my 'models':
class Style {
id: number;
name: string;
make: Make;
model: Model;
year: Year;
submodel: Submodel;
trim: string;
states: string[];
engine: Engine;
transmission: Transmission;
options: Options[];
colors: Color[];
drivenWheels: string;
numOfDoors: string;
squishVins: string[];
categories: Categories;
MPG: MPG;
manufacturerOptionCode: string;
}
export class CarObject {
styles: Style[];
stylesCount: number;
}
My component:
import { CarObject } from './make';
import { EdmundsService } from './edmunds-search-result.service';
#Component({REDACTED
providers: [EdmundsService] })
export class EdmundsSearchResultComponent implements OnInit {
cars: CarObject[];
errorMessage: string;
constructor(private _edmundsService: EdmundsService) { }
getCars(): void {
this._edmundsService.getCars()
.subscribe(
cars => this.cars = cars,
error => this.errorMessage = <any>error);
}
ngOnInit(): void {
this.getCars();
}
}
Component HTML:
{{ cars.stylesCount | async }}
Sample API Response: http://pastebin.com/0LyZuPGW
Error Output:
EXCEPTION: Error in ./EdmundsSearchResultComponent class
EdmundsSearchResultComponent - inline template:0:0 caused by:
Cannot read property 'stylesCount' of undefined
CarObject was designed to match the API Response, so it could be okay to remove the array brackets ( [] )
I don't know why this won't display the object data on my template despite closely following the Tour Of Heroes HTTP/Services tutorial.
What I am trying to do is make an HTTP request from variable 'styleurl' (which I see is successfully made by checking the 'Network' tab in chrome dev tools.) Using this API Response, I want my CarObject to 'consume' the json response, and be available to my component/template.
In your component you're reserving your car property, but you don't initialize it, so it remains undefined.
At the time your HTML renders the promise isn't fulfilled yet, your car is still undefined but you try to access a property from it.
A couple solutions:
preset it:
cars: CarObject = new CarObject(); // or <CarObject>{}
use the elvis operator in your template:
{{ cars?.stylesCount }}
use ngIf:
<div *ngIf="cars">{{ cars.styleCount }}</div>
There are probably a couple of more ways to handle this case.
See my update at the bottom regarding your usage of the async pipe. It probably leads to errors as well in the way you're trying to use it.
Besides, i would suggest reading up on TypeScript types as well as general best practices for angular and typescript especially regarding the usage of models, interfaces and such. Also using Observables would be a good idea instead of Promises.
There are some issues in your code, so this is just a hint, but elaborating on them has no place here i think and aren't the source of your problem.
Hope i could help.
Update:
About your usage of the async pipe:
The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted.
You use it on an array of CarObjects which btw shouldn't be an array.
Take a look at the documentation for the async pipe for proper usage.
I am trying to set up authentication in Angular 2, with the help from the following article (and from a previous question on SO) I managed to create my own extended RouterOutlet:
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes: any;
private parentRouter: Router;
private loginService: LoginService;
constructor(_viewContainerRef: ViewContainerRef, _loader: DynamicComponentLoader,
_parentRouter: Router, #Attribute('name') nameAttr: string,
private loginService: LoginService) {
super(_viewContainerRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
this.publicRoutes = {
'login': true
};
}
_canActivate(url: string, admin: boolean) {
=> Checks with my loginService if user is authenticated
}
activate(instruction: ComponentInstruction) {
if (this._canActivate(url, isAdmin)) {
=> Go to desired URL
} else {
=> Go to login page
}
}
}
The problem with this code is that my typescript generates the following error:
"Duplicate identifier 'loginService'"
My code does function as expected, I just don't like the typescript errors when parsing typescript to javascript. If I rename the second loginService however, my code does break and I can find a
TypeError: this.loginService is undefined
In my console. I was wondering if anybody knows how to solve this problem?
You declare loginService twice in your class
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes: any;
private parentRouter: Router;
// private loginService: LoginService; // <== remove this
and name the parameter loginService instead of loginService2
constructor(_viewContainerRef: ViewContainerRef, _loader: DynamicComponentLoader,
_parentRouter: Router, #Attribute('name') nameAttr: string,
private loginService: LoginService) {
super(_viewContainerRef, _loader, _parentRouter, nameAttr);
A private or public modifier on a constructor parameter already declares a class property with this name. No need to declare the property explicitely again.