title: The correct way to use decorators when logging services in Angular
body: <p>I have two services one is an Auth service and the other is an Analytics service and they exist in different libraries. The analytics service is used to do event logging. One obvious way I could use it to log the <code>auth.service</code> is injecting the analytics service in the auth service but I'd don't want to use this method, I'd like to use the decorator strategy. What is the correct approach to achieve this? Also is it possible to use a decorator without interfering with the auth.service codebase?</p>
  <p><strong>[update]</strong>:
  I've implemented this decorator as shown below (snippet A).
  The decorator is located @ <code>libs/state/analytics/src/lib/decorators/analytics.decorator.ts</code>
  I would like to use it on the Auth service as shown in (snippet B).</p>
  <p>Then in the decorator there is an analytics function I will call from the <code>analytics.service.ts</code>  i.e. the <em>logEvent()</em> function. How do I inject the <em>logEvent()</em> function from analytics.service in this decorator( The main idea behind this is to log the errors and send them to segment for analytics).</p>
  <p><strong>Snippet A</strong></p>
  <pre><code>export const Log = () =&gt; {
  
      return function catchError(target: any, propertyName: any, descriptor: any) {
          const method = descriptor.value;
  
          descriptor.value = function (...args: any) {
              try {
                  return method.apply(target, args);
              } catch (error) {
                  throw new Error(`Special error message: ${error}`);
         
              }
          };
      }
  }
  </code></pre>
  <p><strong>Snippet B</strong>:
  The usecase would be something like this.</p>
  <pre><code>  @Log()
    public async loginWithEmailAndPassword(email: string, password: string)
    {
      return this.afAuth.signInWithEmailAndPassword(email, password)
                .then(() =&gt; {
                  this._logger.log(() =&gt; `AuthService.signInWithEmailAndPassword: Successfully logged user in with Email and Password.`);
                })
                .catch((error) =&gt; {
                  this._throwError(error);
                });
    }
  </code></pre>
  <p><strong>Auth Service</strong> <code>libs/state/analytics/src/lib/services/auth.service';</code></p>
  <pre><code>    @Injectable({ providedIn: 'root' })
      export class AuthService {
        constructor(private afAuth: AngularFireAuth,
                    private afs: AngularFirestore,
                    private router: Router,
                    private _toastService: ToastService,
                    @Inject('ENVIRONMENT') private _env: AuthEnvironment
                    )
        {
         }
      
        public getAuth() {
          return this.afAuth;
        }
      
        public async resetPassword(email: string, langCode: string = 'en' )
        {
      
          firebase.auth().languageCode = langCode;
         
          const actionCodeSettings : firebase.auth.ActionCodeSettings = {
            url: this._env.baseUrl
          }
      
          return firebase.auth()
                     .sendPasswordResetEmail( email, actionCodeSettings )
                     .then(() =&gt; this._toastService.doSimpleToast('A password reset link has been sent to your email address.'))
                     .catch(() =&gt; this._toastService.doSimpleToast('An error occurred while attempting to reset your password. Please contact support.'));
        }
  
  
  
    public async loginWithEmailAndPassword(email: string, password: string)
    {
      return this.afAuth.signInWithEmailAndPassword(email, password)
                .then(() =&gt; {
                  this._logger.log(() =&gt; `AuthService.signInWithEmailAndPassword: Successfully logged user in with Email and Password.`);
                })
                .catch((error) =&gt; {
                  this._throwError(error);
                });
    }
      
    public createUserWithEmailAndPassword(displayName: string, email: string, password: string, userProfile: UserProfile, roles: Roles)
        {
          return this.afAuth
                     .createUserWithEmailAndPassword(email, password)
                     .then((res) =&gt; {
                        this._checkUpdateUserData(res.user, displayName, userProfile, roles);
                        return &lt;User&gt; &lt;unknown&gt; res.user;
                     })
                     .catch((error) =&gt; {
                       this._throwError(error);
                     });
        }
  ...
  </code></pre>
  <p><strong>Analytics</strong> <code>libs/authentication/auth/src/lib/services/analytics.service';</code></p>
  <pre><code>export class AnalyticsService {
  
    user$: Observable&lt;User&gt;;
  
    constructor(
      private _analytics: SegmentService,
      private _cacheService: CacheService,
      private _userService: UserService&lt;User&gt;) {
      this.user$ = this._userService.getUser().pipe(take(1));
    }
  
  
    public logEvent(event: TrackEvent) {
      this.user$.subscribe(user =&gt; {
        const userId = user?user.id: null;
        const userEmail = user?user.email: null;
        const displayName = user?user.displayName: null;
        const roles = user?user.roles: null;
        this._analytics.track(event.name, {
          ...event,
          property_id: propID,
          user_id: userId,
          email: userEmail,
          displayName: displayName,
          roles: roles,
        })
      });
    }
  
    identifyUser() {
      this.user$.subscribe((user: User) =&gt; {
        if (user) {
          const cachedUser = this._cacheService.getValueByKey('ajs_user_id');
          if (!cachedUser) {
            const traits = { userId: user.id, email: user.email, displayName: user.displayName }
            this._analytics.identify(user.id, traits);
          }
        }
      });
    };
  
  ...
  
  
  }
  </code></pre>