001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.loggers;
028    import org.opends.messages.Message;
029    
030    
031    import java.io.File;
032    import java.io.IOException;
033    import java.util.*;
034    
035    import org.opends.server.admin.server.ConfigurationChangeListener;
036    import org.opends.server.admin.std.server.FileBasedAccessLogPublisherCfg;
037    import org.opends.server.admin.std.server.AccessLogPublisherCfg;
038    import org.opends.server.api.*;
039    import org.opends.server.config.ConfigException;
040    import org.opends.server.core.AbandonOperation;
041    import org.opends.server.core.AddOperation;
042    import org.opends.server.core.BindOperation;
043    import org.opends.server.core.CompareOperation;
044    import org.opends.server.core.DeleteOperation;
045    import org.opends.server.core.DirectoryServer;
046    import org.opends.server.core.ExtendedOperation;
047    import org.opends.server.core.ModifyOperation;
048    import org.opends.server.core.ModifyDNOperation;
049    import org.opends.server.core.SearchOperation;
050    import org.opends.server.core.UnbindOperation;
051    import org.opends.server.types.*;
052    import org.opends.server.util.TimeThread;
053    
054    import static org.opends.messages.ConfigMessages.*;
055    
056    import org.opends.messages.MessageBuilder;
057    import static org.opends.server.util.StaticUtils.getFileForPath;
058    import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
059    
060    
061    /**
062     * This class provides the implementation of the access logger used by
063     * the directory server.
064     */
065    public class TextAccessLogPublisher
066        extends AccessLogPublisher<FileBasedAccessLogPublisherCfg>
067        implements ConfigurationChangeListener<FileBasedAccessLogPublisherCfg>
068    {
069      private boolean suppressInternalOperations = true;
070    
071      private boolean suppressSynchronizationOperations = false;
072    
073      private TextWriter writer;
074    
075      private FileBasedAccessLogPublisherCfg currentConfig;
076    
077      /**
078       * Returns an instance of the text access log publisher that will print
079       * all messages to the provided writer. This is used to print the messages
080       * to the console when the server starts up.
081       *
082       * @param writer The text writer where the message will be written to.
083       * @param suppressInternal Indicates whether to suppress internal operations.
084       * @return The instance of the text error log publisher that will print
085       * all messages to standard out.
086       */
087      public static TextAccessLogPublisher
088          getStartupTextAccessPublisher(TextWriter writer, boolean suppressInternal)
089      {
090        TextAccessLogPublisher startupPublisher = new TextAccessLogPublisher();
091        startupPublisher.writer = writer;
092        startupPublisher.suppressInternalOperations = suppressInternal;
093    
094        return startupPublisher;
095      }
096    
097      /**
098       * {@inheritDoc}
099       */
100      public boolean isConfigurationAcceptable(AccessLogPublisherCfg configuration,
101                                               List<Message> unacceptableReasons)
102      {
103        FileBasedAccessLogPublisherCfg config =
104            (FileBasedAccessLogPublisherCfg) configuration;
105        return isConfigurationChangeAcceptable(config, unacceptableReasons);
106      }
107    
108      /**
109       * {@inheritDoc}
110       */
111      public void initializeAccessLogPublisher(
112          FileBasedAccessLogPublisherCfg config)
113          throws ConfigException, InitializationException
114      {
115        File logFile = getFileForPath(config.getLogFile());
116        FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
117    
118        try
119        {
120          FilePermission perm =
121              FilePermission.decodeUNIXMode(config.getLogFilePermissions());
122    
123          LogPublisherErrorHandler errorHandler =
124              new LogPublisherErrorHandler(config.dn());
125    
126          boolean writerAutoFlush =
127              config.isAutoFlush() && !config.isAsynchronous();
128    
129          MultifileTextWriter writer =
130              new MultifileTextWriter("Multifile Text Writer for " +
131                  config.dn().toNormalizedString(),
132                                      config.getTimeInterval(),
133                                      fnPolicy,
134                                      perm,
135                                      errorHandler,
136                                      "UTF-8",
137                                      writerAutoFlush,
138                                      config.isAppend(),
139                                      (int)config.getBufferSize());
140    
141          // Validate retention and rotation policies.
142          for(DN dn : config.getRotationPolicyDNs())
143          {
144            writer.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
145          }
146    
147          for(DN dn: config.getRetentionPolicyDNs())
148          {
149            writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
150          }
151    
152          if(config.isAsynchronous())
153          {
154            this.writer = new AsyncronousTextWriter("Asyncronous Text Writer for " +
155                config.dn().toNormalizedString(), config.getQueueSize(),
156                                                  config.isAutoFlush(),
157                                                  writer);
158          }
159          else
160          {
161            this.writer = writer;
162          }
163        }
164        catch(DirectoryException e)
165        {
166          Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(
167              config.dn().toString(), String.valueOf(e));
168          throw new InitializationException(message, e);
169    
170        }
171        catch(IOException e)
172        {
173          Message message = ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE.get(
174              logFile.toString(), config.dn().toString(), String.valueOf(e));
175          throw new InitializationException(message, e);
176    
177        }
178    
179        suppressInternalOperations = config.isSuppressInternalOperations();
180        suppressSynchronizationOperations =
181          config.isSuppressSynchronizationOperations();
182    
183        currentConfig = config;
184    
185        config.addFileBasedAccessChangeListener(this);
186      }
187    
188    
189    
190      /**
191       * {@inheritDoc}
192       */
193      public boolean isConfigurationChangeAcceptable(
194           FileBasedAccessLogPublisherCfg config, List<Message> unacceptableReasons)
195       {
196         // Make sure the permission is valid.
197         try
198         {
199           FilePermission filePerm =
200               FilePermission.decodeUNIXMode(config.getLogFilePermissions());
201           if(!filePerm.isOwnerWritable())
202           {
203             Message message = ERR_CONFIG_LOGGING_INSANE_MODE.get(
204                 config.getLogFilePermissions());
205             unacceptableReasons.add(message);
206             return false;
207           }
208         }
209         catch(DirectoryException e)
210         {
211           Message message = ERR_CONFIG_LOGGING_MODE_INVALID.get(
212                   config.getLogFilePermissions(), String.valueOf(e));
213           unacceptableReasons.add(message);
214           return false;
215         }
216    
217         return true;
218       }
219    
220      /**
221       * {@inheritDoc}
222       */
223       public ConfigChangeResult applyConfigurationChange(
224           FileBasedAccessLogPublisherCfg config)
225       {
226         // Default result code.
227         ResultCode resultCode = ResultCode.SUCCESS;
228         boolean adminActionRequired = false;
229         ArrayList<Message> messages = new ArrayList<Message>();
230    
231         suppressInternalOperations = config.isSuppressInternalOperations();
232         suppressSynchronizationOperations =
233           config.isSuppressSynchronizationOperations();
234    
235         File logFile = getFileForPath(config.getLogFile());
236         FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
237    
238         try
239         {
240           FilePermission perm =
241               FilePermission.decodeUNIXMode(config.getLogFilePermissions());
242    
243           boolean writerAutoFlush =
244              config.isAutoFlush() && !config.isAsynchronous();
245    
246           TextWriter currentWriter;
247           // Determine the writer we are using. If we were writing asyncronously,
248           // we need to modify the underlaying writer.
249           if(writer instanceof AsyncronousTextWriter)
250           {
251             currentWriter = ((AsyncronousTextWriter)writer).getWrappedWriter();
252           }
253           else
254           {
255             currentWriter = writer;
256           }
257    
258           if(currentWriter instanceof MultifileTextWriter)
259           {
260             MultifileTextWriter mfWriter = (MultifileTextWriter)currentWriter;
261    
262             mfWriter.setNamingPolicy(fnPolicy);
263             mfWriter.setFilePermissions(perm);
264             mfWriter.setAppend(config.isAppend());
265             mfWriter.setAutoFlush(writerAutoFlush);
266             mfWriter.setBufferSize((int)config.getBufferSize());
267             mfWriter.setInterval(config.getTimeInterval());
268    
269             mfWriter.removeAllRetentionPolicies();
270             mfWriter.removeAllRotationPolicies();
271    
272             for(DN dn : config.getRotationPolicyDNs())
273             {
274               mfWriter.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
275             }
276    
277             for(DN dn: config.getRetentionPolicyDNs())
278             {
279               mfWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
280             }
281    
282             if(writer instanceof AsyncronousTextWriter && !config.isAsynchronous())
283             {
284               // The asynronous setting is being turned off.
285               AsyncronousTextWriter asyncWriter = ((AsyncronousTextWriter)writer);
286               writer = mfWriter;
287               asyncWriter.shutdown(false);
288             }
289    
290             if(!(writer instanceof AsyncronousTextWriter) &&
291                 config.isAsynchronous())
292             {
293               // The asynronous setting is being turned on.
294               AsyncronousTextWriter asyncWriter =
295                   new AsyncronousTextWriter("Asyncronous Text Writer for " +
296                       config.dn().toNormalizedString(), config.getQueueSize(),
297                                                         config.isAutoFlush(),
298                                                         mfWriter);
299               writer = asyncWriter;
300             }
301    
302             if((currentConfig.isAsynchronous() && config.isAsynchronous()) &&
303                 (currentConfig.getQueueSize() != config.getQueueSize()))
304             {
305               adminActionRequired = true;
306             }
307    
308             currentConfig = config;
309           }
310         }
311         catch(Exception e)
312         {
313           Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(
314                   config.dn().toString(),
315                   stackTraceToSingleLineString(e));
316           resultCode = DirectoryServer.getServerErrorResultCode();
317           messages.add(message);
318    
319         }
320    
321         return new ConfigChangeResult(resultCode, adminActionRequired, messages);
322       }
323    
324    
325    
326      /**
327       * {@inheritDoc}
328       */
329      public void close()
330      {
331        writer.shutdown();
332    
333        if(currentConfig != null)
334        {
335          currentConfig.removeFileBasedAccessChangeListener(this);
336        }
337      }
338    
339    
340    
341      /**
342       * Writes a message to the access logger with information about a new client
343       * connection that has been established, regardless of whether it will be
344       * immediately terminated.
345       *
346       * @param  clientConnection  The client connection that has been established.
347       */
348      public void logConnect(ClientConnection clientConnection)
349      {
350        long connectionID = clientConnection.getConnectionID();
351    
352        if (connectionID < 0 && suppressInternalOperations)
353        {
354          return;
355        }
356        StringBuilder buffer = new StringBuilder(50);
357        buffer.append("[");
358        buffer.append(TimeThread.getLocalTime());
359        buffer.append("]");
360        buffer.append(" CONNECT conn=");
361        buffer.append(connectionID);
362        buffer.append(" from=");
363        buffer.append(clientConnection.getClientAddress());
364        buffer.append(" to=");
365        buffer.append(clientConnection.getServerAddress());
366        buffer.append(" protocol=");
367        buffer.append(clientConnection.getProtocol());
368    
369        writer.writeRecord(buffer.toString());
370    
371      }
372    
373    
374      /**
375       * Writes a message to the access logger with information about the
376       * termination of an existing client connection.
377       *
378       * @param  clientConnection  The client connection that has been terminated.
379       * @param  disconnectReason  A generic disconnect reason for the connection
380       *                           termination.
381       * @param  message           A human-readable message that can provide
382       *                           additional information about the disconnect.
383       */
384      public void logDisconnect(ClientConnection clientConnection,
385                                DisconnectReason disconnectReason,
386                                Message message)
387      {
388        long connectionID = clientConnection.getConnectionID();
389        if (connectionID < 0 && suppressInternalOperations)
390        {
391          return;
392        }
393        StringBuilder buffer = new StringBuilder(50);
394        buffer.append("[");
395        buffer.append(TimeThread.getLocalTime());
396        buffer.append("]");
397        buffer.append(" DISCONNECT conn=");
398        buffer.append(connectionID);
399        buffer.append(" reason=\"");
400        buffer.append(disconnectReason);
401    
402        if (message != null)
403        {
404          buffer.append("\" msg=\"");
405          buffer.append(message);
406        }
407    
408        buffer.append("\"");
409    
410        writer.writeRecord(buffer.toString());
411      }
412    
413    
414    
415      /**
416       * Writes a message to the access logger with information about the abandon
417       * request associated with the provided abandon operation.
418       *
419       * @param  abandonOperation  The abandon operation containing the information
420       *                           to use to log the abandon request.
421       */
422      public void logAbandonRequest(AbandonOperation abandonOperation)
423      {
424        long connectionID = abandonOperation.getConnectionID();
425        if (connectionID < 0)
426        {
427          // This is an internal operation.
428          if (abandonOperation.isSynchronizationOperation())
429          {
430            if (suppressSynchronizationOperations)
431            {
432              return;
433            }
434          }
435          else
436          {
437            if (suppressInternalOperations)
438            {
439              return;
440            }
441          }
442        }
443    
444        StringBuilder buffer = new StringBuilder(50);
445        buffer.append("[");
446        buffer.append(TimeThread.getLocalTime());
447        buffer.append("]");
448        buffer.append(" ABANDON conn=");
449        buffer.append(connectionID);
450        buffer.append(" op=");
451        buffer.append(abandonOperation.getOperationID());
452        buffer.append(" msgID=");
453        buffer.append(abandonOperation.getMessageID());
454        buffer.append(" idToAbandon=");
455        buffer.append(abandonOperation.getIDToAbandon());
456        if (abandonOperation.isSynchronizationOperation())
457          buffer.append(" type=synchronization");
458    
459        writer.writeRecord(buffer.toString());
460      }
461    
462      /**
463       * Writes a message to the access logger with information about the result
464       * of the provided abandon operation.
465       *
466       * @param  abandonOperation  The abandon operation containing the information
467       *                           to use to log the abandon request.
468       */
469      public void logAbandonResult(AbandonOperation abandonOperation)
470      {
471        long connectionID = abandonOperation.getConnectionID();
472        if (connectionID < 0)
473        {
474          // This is an internal operation.
475          if (abandonOperation.isSynchronizationOperation())
476          {
477            if (suppressSynchronizationOperations)
478            {
479              return;
480            }
481          }
482          else
483          {
484            if (suppressInternalOperations)
485            {
486              return;
487            }
488          }
489        }
490        StringBuilder buffer = new StringBuilder(50);
491        buffer.append("[");
492        buffer.append(TimeThread.getLocalTime());
493        buffer.append("]");
494        buffer.append(" ABANDON conn=");
495        buffer.append(connectionID);
496        buffer.append(" op=");
497        buffer.append(abandonOperation.getOperationID());
498        buffer.append(" msgID=");
499        buffer.append(abandonOperation.getMessageID());
500        buffer.append(" result=");
501        buffer.append(abandonOperation.getResultCode());
502    
503        MessageBuilder msg = abandonOperation.getErrorMessage();
504        if ((msg != null) && (msg.length() > 0))
505        {
506          buffer.append(" message=\"");
507          buffer.append(msg);
508          buffer.append("\"");
509        }
510    
511        msg = abandonOperation.getAdditionalLogMessage();
512        if ((msg != null) && (msg.length() > 0))
513        {
514          buffer.append(" additionalInfo=\"");
515          buffer.append(msg);
516          buffer.append("\"");
517        }
518    
519        buffer.append(" etime=");
520        buffer.append(abandonOperation.getProcessingTime());
521    
522        writer.writeRecord(buffer.toString());
523      }
524    
525    
526      /**
527       * Writes a message to the access logger with information about the add
528       * request associated with the provided add operation.
529       *
530       * @param  addOperation  The add operation containing the information to use
531       *                       to log the add request.
532       */
533      public void logAddRequest(AddOperation addOperation)
534      {
535        long connectionID = addOperation.getConnectionID();
536        if (connectionID < 0)
537        {
538          // This is an internal operation.
539          if (addOperation.isSynchronizationOperation())
540          {
541            if (suppressSynchronizationOperations)
542            {
543              return;
544            }
545          }
546          else
547          {
548            if (suppressInternalOperations)
549            {
550              return;
551            }
552          }
553        }
554        StringBuilder buffer = new StringBuilder(50);
555        buffer.append("[");
556        buffer.append(TimeThread.getLocalTime());
557        buffer.append("]");
558        buffer.append(" ADD conn=");
559        buffer.append(connectionID);
560        buffer.append(" op=");
561        buffer.append(addOperation.getOperationID());
562        buffer.append(" msgID=");
563        buffer.append(addOperation.getMessageID());
564        buffer.append(" dn=\"");
565        addOperation.getRawEntryDN().toString(buffer);
566        buffer.append("\"");
567        if (addOperation.isSynchronizationOperation())
568          buffer.append(" type=synchronization");
569    
570    
571        writer.writeRecord(buffer.toString());
572      }
573    
574    
575      /**
576       * Writes a message to the access logger with information about the add
577       * response associated with the provided add operation.
578       *
579       * @param  addOperation  The add operation containing the information to use
580       *                       to log the add response.
581       */
582      public void logAddResponse(AddOperation addOperation)
583      {
584        long connectionID = addOperation.getConnectionID();
585        if (connectionID < 0)
586        {
587          // This is an internal operation.
588          if (addOperation.isSynchronizationOperation())
589          {
590            if (suppressSynchronizationOperations)
591            {
592              return;
593            }
594          }
595          else
596          {
597            if (suppressInternalOperations)
598            {
599              return;
600            }
601          }
602        }
603        StringBuilder buffer = new StringBuilder(50);
604        buffer.append("[");
605        buffer.append(TimeThread.getLocalTime());
606        buffer.append("]");
607        buffer.append(" ADD conn=");
608        buffer.append(connectionID);
609        buffer.append(" op=");
610        buffer.append(addOperation.getOperationID());
611        buffer.append(" msgID=");
612        buffer.append(addOperation.getMessageID());
613        buffer.append(" result=\"");
614        buffer.append(addOperation.getResultCode());
615    
616        MessageBuilder msg = addOperation.getErrorMessage();
617        if ((msg != null) && (msg.length() > 0))
618        {
619          buffer.append("\" message=\"");
620          buffer.append(msg);
621        }
622    
623        msg = addOperation.getAdditionalLogMessage();
624        if ((msg != null) && (msg.length() > 0))
625        {
626          buffer.append("\" additionalInfo=\"");
627          buffer.append(msg);
628        }
629    
630        DN proxiedAuthDN = addOperation.getProxiedAuthorizationDN();
631        if (proxiedAuthDN != null)
632        {
633          buffer.append("\" authzDN=\"");
634          proxiedAuthDN.toString(buffer);
635        }
636    
637        buffer.append("\" etime=");
638        buffer.append(addOperation.getProcessingTime());
639    
640        writer.writeRecord(buffer.toString());
641      }
642    
643    
644    
645      /**
646       * Writes a message to the access logger with information about the bind
647       * request associated with the provided bind operation.
648       *
649       * @param  bindOperation  The bind operation with the information to use
650       *                        to log the bind request.
651       */
652      public void logBindRequest(BindOperation bindOperation)
653      {
654        long connectionID = bindOperation.getConnectionID();
655        if (connectionID < 0)
656        {
657          // This is an internal operation.
658          if (bindOperation.isSynchronizationOperation())
659          {
660            if (suppressSynchronizationOperations)
661            {
662              return;
663            }
664          }
665          else
666          {
667            if (suppressInternalOperations)
668            {
669              return;
670            }
671          }
672        }
673        StringBuilder buffer = new StringBuilder(50);
674        buffer.append("[");
675        buffer.append(TimeThread.getLocalTime());
676        buffer.append("]");
677        buffer.append(" BIND conn=");
678        buffer.append(connectionID);
679        buffer.append(" op=");
680        buffer.append(bindOperation.getOperationID());
681        buffer.append(" msgID=");
682        buffer.append(bindOperation.getMessageID());
683    
684        switch (bindOperation.getAuthenticationType())
685        {
686          case SIMPLE:
687            buffer.append(" type=SIMPLE");
688            break;
689          case SASL:
690            buffer.append(" type=SASL mechanism=");
691            buffer.append(bindOperation.getSASLMechanism());
692            break;
693          default:
694            buffer.append(" type=");
695            buffer.append(bindOperation.getAuthenticationType());
696            break;
697        }
698    
699        buffer.append(" dn=\"");
700        bindOperation.getRawBindDN().toString(buffer);
701        buffer.append("\"");
702        if (bindOperation.isSynchronizationOperation())
703          buffer.append(" type=synchronization");
704    
705    
706        writer.writeRecord(buffer.toString());
707      }
708    
709    
710      /**
711       * Writes a message to the access logger with information about the bind
712       * response associated with the provided bind operation.
713       *
714       * @param  bindOperation  The bind operation containing the information to use
715       *                        to log the bind response.
716       */
717      public void logBindResponse(BindOperation bindOperation)
718      {
719        long connectionID = bindOperation.getConnectionID();
720        if (connectionID < 0)
721        {
722          // This is an internal operation.
723          if (bindOperation.isSynchronizationOperation())
724          {
725            if (suppressSynchronizationOperations)
726            {
727              return;
728            }
729          }
730          else
731          {
732            if (suppressInternalOperations)
733            {
734              return;
735            }
736          }
737        }
738        StringBuilder buffer = new StringBuilder(50);
739        buffer.append("[");
740        buffer.append(TimeThread.getLocalTime());
741        buffer.append("]");
742        buffer.append(" BIND conn=");
743        buffer.append(connectionID);
744        buffer.append(" op=");
745        buffer.append(bindOperation.getOperationID());
746        buffer.append(" msgID=");
747        buffer.append(bindOperation.getMessageID());
748        buffer.append(" result=\"");
749        buffer.append(bindOperation.getResultCode());
750    
751        MessageBuilder msg = bindOperation.getErrorMessage();
752        if ((msg != null) && (msg.length() > 0))
753        {
754          buffer.append("\" message=\"");
755          buffer.append(msg);
756        }
757    
758        Message failureMessage = bindOperation.getAuthFailureReason();
759        if (failureMessage != null)
760        {
761          buffer.append("\" authFailureID=");
762          buffer.append(failureMessage.getDescriptor().getId());
763          buffer.append(" authFailureReason=\"");
764          buffer.append(failureMessage);
765        }
766    
767        msg = bindOperation.getAdditionalLogMessage();
768        if ((msg != null) && (msg.length() > 0))
769        {
770          buffer.append("\" additionalInfo=\"");
771          buffer.append(msg);
772        }
773    
774        if (bindOperation.getResultCode() == ResultCode.SUCCESS)
775        {
776          AuthenticationInfo authInfo = bindOperation.getAuthenticationInfo();
777          if (authInfo != null)
778          {
779            DN authDN = authInfo.getAuthenticationDN();
780            buffer.append("\" authDN=\"");
781            if (authDN != null)
782            {
783              authDN.toString(buffer);
784    
785              DN authzDN = authInfo.getAuthorizationDN();
786              if (! authDN.equals(authzDN))
787              {
788                buffer.append("\" authzDN=\"");
789                if (authzDN != null)
790                {
791                  authzDN.toString(buffer);
792                }
793              }
794            }
795          }
796        }
797    
798        buffer.append("\" etime=");
799        long etime = bindOperation.getProcessingNanoTime();
800        if(etime <= -1)
801        {
802          etime = bindOperation.getProcessingTime();
803        }
804        buffer.append(etime);
805    
806        writer.writeRecord(buffer.toString());
807      }
808    
809    
810      /**
811       * Writes a message to the access logger with information about the compare
812       * request associated with the provided compare operation.
813       *
814       * @param  compareOperation  The compare operation containing the information
815       *                           to use to log the compare request.
816       */
817      public void logCompareRequest(CompareOperation compareOperation)
818      {
819        long connectionID = compareOperation.getConnectionID();
820        if (connectionID < 0)
821        {
822          // This is an internal operation.
823          if (compareOperation.isSynchronizationOperation())
824          {
825            if (suppressSynchronizationOperations)
826            {
827              return;
828            }
829          }
830          else
831          {
832            if (suppressInternalOperations)
833            {
834              return;
835            }
836          }
837        }
838        StringBuilder buffer = new StringBuilder(50);
839        buffer.append("[");
840        buffer.append(TimeThread.getLocalTime());
841        buffer.append("]");
842        buffer.append(" COMPARE conn=");
843        buffer.append(connectionID);
844        buffer.append(" op=");
845        buffer.append(compareOperation.getOperationID());
846        buffer.append(" msgID=");
847        buffer.append(compareOperation.getMessageID());
848        buffer.append(" dn=\"");
849        compareOperation.getRawEntryDN().toString(buffer);
850        buffer.append("\" attr=");
851        buffer.append(compareOperation.getAttributeType());
852        if (compareOperation.isSynchronizationOperation())
853          buffer.append(" type=synchronization");
854    
855    
856        writer.writeRecord(buffer.toString());
857      }
858    
859    
860      /**
861       * Writes a message to the access logger with information about the compare
862       * response associated with the provided compare operation.
863       *
864       * @param  compareOperation  The compare operation containing the information
865       *                           to use to log the compare response.
866       */
867      public void logCompareResponse(CompareOperation compareOperation)
868      {
869        long connectionID = compareOperation.getConnectionID();
870        if (connectionID < 0)
871        {
872          // This is an internal operation.
873          if (compareOperation.isSynchronizationOperation())
874          {
875            if (suppressSynchronizationOperations)
876            {
877              return;
878            }
879          }
880          else
881          {
882            if (suppressInternalOperations)
883            {
884              return;
885            }
886          }
887        }
888        StringBuilder buffer = new StringBuilder(50);
889        buffer.append("[");
890        buffer.append(TimeThread.getLocalTime());
891        buffer.append("]");
892        buffer.append(" COMPARE conn=");
893        buffer.append(connectionID);
894        buffer.append(" op=");
895        buffer.append(compareOperation.getOperationID());
896        buffer.append(" msgID=");
897        buffer.append(compareOperation.getMessageID());
898        buffer.append(" result=\"");
899        buffer.append(compareOperation.getResultCode());
900    
901        MessageBuilder msg = compareOperation.getErrorMessage();
902        if ((msg != null) && (msg.length() > 0))
903        {
904          buffer.append("\" message=\"");
905          buffer.append(msg);
906        }
907    
908        msg = compareOperation.getAdditionalLogMessage();
909        if ((msg != null) && (msg.length() > 0))
910        {
911          buffer.append("\" additionalInfo=\"");
912          buffer.append(msg);
913        }
914    
915        DN proxiedAuthDN = compareOperation.getProxiedAuthorizationDN();
916        if (proxiedAuthDN != null)
917        {
918          buffer.append("\" authzDN=\"");
919          proxiedAuthDN.toString(buffer);
920        }
921    
922        buffer.append("\" etime=");
923        long etime = compareOperation.getProcessingNanoTime();
924        if(etime <= -1)
925        {
926          etime = compareOperation.getProcessingTime();
927        }
928        buffer.append(etime);
929    
930        writer.writeRecord(buffer.toString());
931      }
932    
933    
934      /**
935       * Writes a message to the access logger with information about the delete
936       * request associated with the provided delete operation.
937       *
938       * @param  deleteOperation  The delete operation with the information to
939       *                          use to log the delete request.
940       */
941      public void logDeleteRequest(DeleteOperation deleteOperation)
942      {
943        long connectionID = deleteOperation.getConnectionID();
944        if (connectionID < 0)
945        {
946          // This is an internal operation.
947          if (deleteOperation.isSynchronizationOperation())
948          {
949            if (suppressSynchronizationOperations)
950            {
951              return;
952            }
953          }
954          else
955          {
956            if (suppressInternalOperations)
957            {
958              return;
959            }
960          }
961        }
962        StringBuilder buffer = new StringBuilder(50);
963        buffer.append("[");
964        buffer.append(TimeThread.getLocalTime());
965        buffer.append("]");
966        buffer.append(" DELETE conn=");
967        buffer.append(connectionID);
968        buffer.append(" op=");
969        buffer.append(deleteOperation.getOperationID());
970        buffer.append(" msgID=");
971        buffer.append(deleteOperation.getMessageID());
972        buffer.append(" dn=\"");
973        deleteOperation.getRawEntryDN().toString(buffer);
974        buffer.append("\"");
975        if (deleteOperation.isSynchronizationOperation())
976          buffer.append(" type=synchronization");
977    
978    
979    
980        writer.writeRecord(buffer.toString());
981      }
982    
983    
984      /**
985       * Writes a message to the access logger with information about the delete
986       * response associated with the provided delete operation.
987       *
988       * @param  deleteOperation The delete operation containing the information to
989       *                           use to log the delete response.
990       */
991      public void logDeleteResponse(DeleteOperation deleteOperation)
992      {
993        long connectionID = deleteOperation.getConnectionID();
994        if (connectionID < 0)
995        {
996          // This is an internal operation.
997          if (deleteOperation.isSynchronizationOperation())
998          {
999            if (suppressSynchronizationOperations)
1000            {
1001              return;
1002            }
1003          }
1004          else
1005          {
1006            if (suppressInternalOperations)
1007            {
1008              return;
1009            }
1010          }
1011        }
1012        StringBuilder buffer = new StringBuilder(50);
1013        buffer.append("[");
1014        buffer.append(TimeThread.getLocalTime());
1015        buffer.append("]");
1016        buffer.append(" DELETE conn=");
1017        buffer.append(connectionID);
1018        buffer.append(" op=");
1019        buffer.append(deleteOperation.getOperationID());
1020        buffer.append(" msgID=");
1021        buffer.append(deleteOperation.getMessageID());
1022        buffer.append(" result=\"");
1023        buffer.append(deleteOperation.getResultCode());
1024    
1025        MessageBuilder msg = deleteOperation.getErrorMessage();
1026        if ((msg != null) && (msg.length() > 0))
1027        {
1028          buffer.append("\" message=\"");
1029          buffer.append(msg);
1030        }
1031    
1032        msg = deleteOperation.getAdditionalLogMessage();
1033        if ((msg != null) && (msg.length() > 0))
1034        {
1035          buffer.append("\" additionalInfo=\"");
1036          buffer.append(msg);
1037        }
1038    
1039        DN proxiedAuthDN = deleteOperation.getProxiedAuthorizationDN();
1040        if (proxiedAuthDN != null)
1041        {
1042          buffer.append("\" authzDN=\"");
1043          proxiedAuthDN.toString(buffer);
1044        }
1045    
1046        buffer.append("\" etime=");
1047        long etime = deleteOperation.getProcessingNanoTime();
1048        if(etime <= -1)
1049        {
1050          etime = deleteOperation.getProcessingTime();
1051        }
1052        buffer.append(etime);
1053    
1054        writer.writeRecord(buffer.toString());
1055      }
1056    
1057    
1058    
1059      /**
1060       * Writes a message to the access logger with information about the extended
1061       * request associated with the provided extended operation.
1062       *
1063       * @param  extendedOperation  The extended operation containing the
1064       *                            information to use to log the extended request.
1065       */
1066      public void logExtendedRequest(ExtendedOperation extendedOperation)
1067      {
1068        long connectionID = extendedOperation.getConnectionID();
1069        if (connectionID < 0)
1070        {
1071          // This is an internal operation.
1072          if (extendedOperation.isSynchronizationOperation())
1073          {
1074            if (suppressSynchronizationOperations)
1075            {
1076              return;
1077            }
1078          }
1079          else
1080          {
1081            if (suppressInternalOperations)
1082            {
1083              return;
1084            }
1085          }
1086        }
1087        StringBuilder buffer = new StringBuilder(50);
1088        buffer.append("[");
1089        buffer.append(TimeThread.getLocalTime());
1090        buffer.append("]");
1091        buffer.append(" EXTENDED conn=");
1092        buffer.append(connectionID);
1093        buffer.append(" op=");
1094        buffer.append(extendedOperation.getOperationID());
1095        buffer.append(" msgID=");
1096        buffer.append(extendedOperation.getMessageID());
1097        buffer.append(" oid=\"");
1098        buffer.append(extendedOperation.getRequestOID());
1099        buffer.append("\"");
1100        if (extendedOperation.isSynchronizationOperation())
1101          buffer.append(" type=synchronization");
1102    
1103    
1104        writer.writeRecord(buffer.toString());
1105      }
1106    
1107    
1108    
1109      /**
1110       * Writes a message to the access logger with information about the extended
1111       * response associated with the provided extended operation.
1112       *
1113       * @param  extendedOperation  The extended operation containing the
1114       *                            info to use to log the extended response.
1115       */
1116      public void logExtendedResponse(ExtendedOperation extendedOperation)
1117      {
1118        long connectionID = extendedOperation.getConnectionID();
1119        if (connectionID < 0)
1120        {
1121          // This is an internal operation.
1122          if (extendedOperation.isSynchronizationOperation())
1123          {
1124            if (suppressSynchronizationOperations)
1125            {
1126              return;
1127            }
1128          }
1129          else
1130          {
1131            if (suppressInternalOperations)
1132            {
1133              return;
1134            }
1135          }
1136        }
1137        StringBuilder buffer = new StringBuilder(50);
1138        buffer.append("[");
1139        buffer.append(TimeThread.getLocalTime());
1140        buffer.append("]");
1141        buffer.append(" EXTENDED conn=");
1142        buffer.append(connectionID);
1143        buffer.append(" op=");
1144        buffer.append(extendedOperation.getOperationID());
1145        buffer.append(" msgID=");
1146        buffer.append(extendedOperation.getMessageID());
1147    
1148        String oid = extendedOperation.getResponseOID();
1149        if (oid != null)
1150        {
1151          buffer.append(" oid=\"");
1152          buffer.append(oid);
1153          buffer.append("\"");
1154        }
1155    
1156        buffer.append(" result=\"");
1157        buffer.append(extendedOperation.getResultCode());
1158    
1159        MessageBuilder msg = extendedOperation.getErrorMessage();
1160        if ((msg != null) && (msg.length() > 0))
1161        {
1162          buffer.append("\" message=\"");
1163          buffer.append(msg);
1164        }
1165    
1166        msg = extendedOperation.getAdditionalLogMessage();
1167        if ((msg != null) && (msg.length() > 0))
1168        {
1169          buffer.append("\" additionalInfo=\"");
1170          buffer.append(msg);
1171        }
1172    
1173        buffer.append("\" etime=");
1174        long etime = extendedOperation.getProcessingNanoTime();
1175        if(etime <= -1)
1176        {
1177          etime = extendedOperation.getProcessingTime();
1178        }
1179        buffer.append(etime);
1180    
1181        writer.writeRecord(buffer.toString());
1182      }
1183    
1184    
1185    
1186      /**
1187       * Writes a message to the access logger with information about the modify
1188       * request associated with the provided modify operation.
1189       *
1190       * @param  modifyOperation The modify operation containing the information to
1191       *                         use to log the modify request.
1192       */
1193      public void logModifyRequest(ModifyOperation modifyOperation)
1194      {
1195        long connectionID = modifyOperation.getConnectionID();
1196        if (connectionID < 0)
1197        {
1198          // This is an internal operation.
1199          if (modifyOperation.isSynchronizationOperation())
1200          {
1201            if (suppressSynchronizationOperations)
1202            {
1203              return;
1204            }
1205          }
1206          else
1207          {
1208            if (suppressInternalOperations)
1209            {
1210              return;
1211            }
1212          }
1213        }
1214        StringBuilder buffer = new StringBuilder(50);
1215        buffer.append("[");
1216        buffer.append(TimeThread.getLocalTime());
1217        buffer.append("]");
1218        buffer.append(" MODIFY conn=");
1219        buffer.append(connectionID);
1220        buffer.append(" op=");
1221        buffer.append(modifyOperation.getOperationID());
1222        buffer.append(" msgID=");
1223        buffer.append(modifyOperation.getMessageID());
1224        buffer.append(" dn=\"");
1225        modifyOperation.getRawEntryDN().toString(buffer);
1226        buffer.append("\"");
1227        if (modifyOperation.isSynchronizationOperation())
1228          buffer.append(" type=synchronization");
1229    
1230    
1231        writer.writeRecord(buffer.toString());
1232      }
1233    
1234    
1235    
1236      /**
1237       * Writes a message to the access logger with information about the modify
1238       * response associated with the provided modify operation.
1239       *
1240       * @param  modifyOperation The modify operation containing the information to
1241       *                         use to log the modify response.
1242       */
1243      public void logModifyResponse(ModifyOperation modifyOperation)
1244      {
1245        long connectionID = modifyOperation.getConnectionID();
1246        if (connectionID < 0)
1247        {
1248          // this is an internal operation
1249          if (modifyOperation.isSynchronizationOperation())
1250          {
1251            if (suppressSynchronizationOperations)
1252            {
1253              return;
1254            }
1255          }
1256          else
1257          {
1258            if (suppressInternalOperations)
1259            {
1260              return;
1261            }
1262          }
1263        }
1264        StringBuilder buffer = new StringBuilder(50);
1265        buffer.append("[");
1266        buffer.append(TimeThread.getLocalTime());
1267        buffer.append("]");
1268        buffer.append(" MODIFY conn=");
1269        buffer.append(connectionID);
1270        buffer.append(" op=");
1271        buffer.append(modifyOperation.getOperationID());
1272        buffer.append(" msgID=");
1273        buffer.append(modifyOperation.getMessageID());
1274        buffer.append(" result=\"");
1275        buffer.append(modifyOperation.getResultCode());
1276    
1277        MessageBuilder msg = modifyOperation.getErrorMessage();
1278        if ((msg != null) && (msg.length() > 0))
1279        {
1280          buffer.append("\" message=\"");
1281          buffer.append(msg);
1282        }
1283    
1284        msg = modifyOperation.getAdditionalLogMessage();
1285        if ((msg != null) && (msg.length() > 0))
1286        {
1287          buffer.append("\" additionalInfo=\"");
1288          buffer.append(msg);
1289        }
1290    
1291        DN proxiedAuthDN = modifyOperation.getProxiedAuthorizationDN();
1292        if (proxiedAuthDN != null)
1293        {
1294          buffer.append("\" authzDN=\"");
1295          proxiedAuthDN.toString(buffer);
1296        }
1297    
1298        buffer.append("\" etime=");
1299        long etime = modifyOperation.getProcessingNanoTime();
1300        if(etime <= -1)
1301        {
1302          etime = modifyOperation.getProcessingTime();
1303        }
1304        buffer.append(etime);
1305    
1306        writer.writeRecord(buffer.toString());
1307      }
1308    
1309    
1310    
1311      /**
1312       * Writes a message to the access logger with information about the modify DN
1313       * request associated with the provided modify DN operation.
1314       *
1315       * @param  modifyDNOperation  The modify DN operation containing the
1316       *                            info to use to log the modify DN request.
1317       */
1318      public void logModifyDNRequest(ModifyDNOperation modifyDNOperation)
1319      {
1320        long connectionID = modifyDNOperation.getConnectionID();
1321        if (connectionID < 0)
1322        {
1323          // This is an internal operation.
1324          if (modifyDNOperation.isSynchronizationOperation())
1325          {
1326            if (suppressSynchronizationOperations)
1327            {
1328              return;
1329            }
1330          }
1331          else
1332          {
1333            if (suppressInternalOperations)
1334            {
1335              return;
1336            }
1337          }
1338        }
1339        StringBuilder buffer = new StringBuilder(50);
1340        buffer.append("[");
1341        buffer.append(TimeThread.getLocalTime());
1342        buffer.append("]");
1343        buffer.append(" MODIFYDN conn=");
1344        buffer.append(connectionID);
1345        buffer.append(" op=");
1346        buffer.append(modifyDNOperation.getOperationID());
1347        buffer.append(" msgID=");
1348        buffer.append(modifyDNOperation.getMessageID());
1349        buffer.append(" dn=\"");
1350        modifyDNOperation.getRawEntryDN().toString(buffer);
1351        buffer.append("\" newRDN=\"");
1352        modifyDNOperation.getRawNewRDN().toString(buffer);
1353        buffer.append("\" deleteOldRDN=");
1354        buffer.append(modifyDNOperation.deleteOldRDN());
1355    
1356        ByteString newSuperior = modifyDNOperation.getRawNewSuperior();
1357        if (newSuperior != null)
1358        {
1359          buffer.append(" newSuperior=\"");
1360          newSuperior.toString(buffer);
1361        }
1362        if (modifyDNOperation.isSynchronizationOperation())
1363          buffer.append(" type=synchronization");
1364    
1365    
1366        writer.writeRecord(buffer.toString());
1367      }
1368    
1369    
1370    
1371      /**
1372       * Writes a message to the access logger with information about the modify DN
1373       * response associated with the provided modify DN operation.
1374       *
1375       * @param  modifyDNOperation  The modify DN operation containing the
1376       *                            information to use to log the modify DN
1377       *                            response.
1378       */
1379      public void logModifyDNResponse(ModifyDNOperation modifyDNOperation)
1380      {
1381        long connectionID = modifyDNOperation.getConnectionID();
1382        if (connectionID < 0)
1383        {
1384          // This is an internal operation.
1385          if (modifyDNOperation.isSynchronizationOperation())
1386          {
1387            if (suppressSynchronizationOperations)
1388            {
1389              return;
1390            }
1391          }
1392          else
1393          {
1394            if (suppressInternalOperations)
1395            {
1396              return;
1397            }
1398          }
1399        }
1400        StringBuilder buffer = new StringBuilder(50);
1401        buffer.append("[");
1402        buffer.append(TimeThread.getLocalTime());
1403        buffer.append("]");
1404        buffer.append(" MODIFYDN conn=");
1405        buffer.append(connectionID);
1406        buffer.append(" op=");
1407        buffer.append(modifyDNOperation.getOperationID());
1408        buffer.append(" msgID=");
1409        buffer.append(modifyDNOperation.getMessageID());
1410        buffer.append(" result=\"");
1411        buffer.append(modifyDNOperation.getResultCode());
1412    
1413        MessageBuilder msg = modifyDNOperation.getErrorMessage();
1414        if ((msg != null) && (msg.length() > 0))
1415        {
1416          buffer.append("\" message=\"");
1417          buffer.append(msg);
1418        }
1419    
1420        msg = modifyDNOperation.getAdditionalLogMessage();
1421        if ((msg != null) && (msg.length() > 0))
1422        {
1423          buffer.append("\" additionalInfo=\"");
1424          buffer.append(msg);
1425        }
1426    
1427        DN proxiedAuthDN = modifyDNOperation.getProxiedAuthorizationDN();
1428        if (proxiedAuthDN != null)
1429        {
1430          buffer.append("\" authzDN=\"");
1431          proxiedAuthDN.toString(buffer);
1432        }
1433    
1434        buffer.append("\" etime=");
1435        long etime = modifyDNOperation.getProcessingNanoTime();
1436        if(etime <= -1)
1437        {
1438          etime = modifyDNOperation.getProcessingTime();
1439        }
1440        buffer.append(etime);
1441    
1442        writer.writeRecord(buffer.toString());
1443      }
1444    
1445    
1446      /**
1447       * Writes a message to the access logger with information about the search
1448       * request associated with the provided search operation.
1449       *
1450       * @param  searchOperation  The search operation containing the info to
1451       *                          use to log the search request.
1452       */
1453      public void logSearchRequest(SearchOperation searchOperation)
1454      {
1455        long connectionID = searchOperation.getConnectionID();
1456        if (connectionID < 0)
1457        {
1458          // This is an internal operation.
1459          if (searchOperation.isSynchronizationOperation())
1460          {
1461            if (suppressSynchronizationOperations)
1462            {
1463              return;
1464            }
1465          }
1466          else
1467          {
1468            if (suppressInternalOperations)
1469            {
1470              return;
1471            }
1472          }
1473        }
1474        StringBuilder buffer = new StringBuilder(50);
1475        buffer.append("[");
1476        buffer.append(TimeThread.getLocalTime());
1477        buffer.append("]");
1478        buffer.append(" SEARCH conn=");
1479        buffer.append(connectionID);
1480        buffer.append(" op=");
1481        buffer.append(searchOperation.getOperationID());
1482        buffer.append(" msgID=");
1483        buffer.append(searchOperation.getMessageID());
1484        buffer.append(" base=\"");
1485        searchOperation.getRawBaseDN().toString(buffer);
1486        buffer.append("\" scope=");
1487        buffer.append(searchOperation.getScope());
1488        buffer.append(" filter=\"");
1489        searchOperation.getRawFilter().toString(buffer);
1490    
1491        LinkedHashSet<String> attrs = searchOperation.getAttributes();
1492        if ((attrs == null) || attrs.isEmpty())
1493        {
1494          buffer.append("\" attrs=\"ALL\"");
1495        }
1496        else
1497        {
1498          buffer.append("\" attrs=\"");
1499    
1500          Iterator<String> iterator = attrs.iterator();
1501          buffer.append(iterator.next());
1502          while (iterator.hasNext())
1503          {
1504            buffer.append(",");
1505            buffer.append(iterator.next());
1506          }
1507    
1508          buffer.append("\"");
1509        }
1510        if (searchOperation.isSynchronizationOperation())
1511          buffer.append(" type=synchronization");
1512    
1513    
1514        writer.writeRecord(buffer.toString());
1515      }
1516    
1517    
1518      /**
1519       * Writes a message to the access logger with information about the search
1520       * result entry that matches the criteria associated with the provided search
1521       * operation.
1522       *
1523       * @param  searchOperation  The search operation with which the search result
1524       *                          entry is associated.
1525       * @param  searchEntry      The search result entry to be logged.
1526       */
1527      public void logSearchResultEntry(SearchOperation searchOperation,
1528                                         SearchResultEntry searchEntry)
1529      {
1530        // NYI
1531      }
1532    
1533    
1534      /**
1535       * Writes a message to the access logger with information about the search
1536       * result reference returned while processing the associated search
1537       * operation.
1538       *
1539       * @param  searchOperation  The search operation with which the search result
1540       *                          reference is associated.
1541       * @param  searchReference  The search result reference to be logged.
1542       */
1543      public void logSearchResultReference(SearchOperation searchOperation,
1544                                SearchResultReference searchReference)
1545      {
1546        // NYI
1547      }
1548    
1549    
1550    
1551      /**
1552       * Writes a message to the access logger with information about the
1553       * completion of the provided search operation.
1554       *
1555       * @param  searchOperation  The search operation containing the information
1556       *                          to use to log the search result done message.
1557       */
1558      public void logSearchResultDone(SearchOperation searchOperation)
1559      {
1560        long connectionID = searchOperation.getConnectionID();
1561        if (connectionID < 0)
1562        {
1563          // This is an internal operation.
1564          if (searchOperation.isSynchronizationOperation())
1565          {
1566            if (suppressSynchronizationOperations)
1567            {
1568              return;
1569            }
1570          }
1571          else
1572          {
1573            if (suppressInternalOperations)
1574            {
1575              return;
1576            }
1577          }
1578        }
1579        StringBuilder buffer = new StringBuilder(50);
1580        buffer.append("[");
1581        buffer.append(TimeThread.getLocalTime());
1582        buffer.append("]");
1583        buffer.append(" SEARCH conn=");
1584        buffer.append(connectionID);
1585        buffer.append(" op=");
1586        buffer.append(searchOperation.getOperationID());
1587        buffer.append(" msgID=");
1588        buffer.append(searchOperation.getMessageID());
1589        buffer.append(" result=\"");
1590        buffer.append(searchOperation.getResultCode());
1591    
1592        MessageBuilder msg = searchOperation.getErrorMessage();
1593        if ((msg != null) && (msg.length() > 0))
1594        {
1595          buffer.append("\" message=\"");
1596          buffer.append(msg);
1597        }
1598    
1599        buffer.append("\" nentries=");
1600        buffer.append(searchOperation.getEntriesSent());
1601    
1602        msg = searchOperation.getAdditionalLogMessage();
1603        if ((msg != null) && (msg.length() > 0))
1604        {
1605          buffer.append(" additionalInfo=\"");
1606          buffer.append(msg);
1607          buffer.append("\"");
1608        }
1609    
1610        DN proxiedAuthDN = searchOperation.getProxiedAuthorizationDN();
1611        if (proxiedAuthDN != null)
1612        {
1613          buffer.append(" authzDN=\"");
1614          proxiedAuthDN.toString(buffer);
1615          buffer.append("\"");
1616        }
1617    
1618        buffer.append(" etime=");
1619        long etime = searchOperation.getProcessingNanoTime();
1620        if(etime <= -1)
1621        {
1622          etime = searchOperation.getProcessingTime();
1623        }
1624        buffer.append(etime);
1625    
1626        writer.writeRecord(buffer.toString());
1627      }
1628    
1629    
1630    
1631      /**
1632       * Writes a message to the access logger with information about the unbind
1633       * request associated with the provided unbind operation.
1634       *
1635       * @param  unbindOperation  The unbind operation containing the info to
1636       *                          use to log the unbind request.
1637       */
1638      public void logUnbind(UnbindOperation unbindOperation)
1639      {
1640        long connectionID = unbindOperation.getConnectionID();
1641        if (connectionID < 0)
1642        {
1643          // This is an internal operation.
1644          if (unbindOperation.isSynchronizationOperation())
1645          {
1646            if (suppressSynchronizationOperations)
1647            {
1648              return;
1649            }
1650          }
1651          else
1652          {
1653            if (suppressInternalOperations)
1654            {
1655              return;
1656            }
1657          }
1658        }
1659        StringBuilder buffer = new StringBuilder(50);
1660        buffer.append("[");
1661        buffer.append(TimeThread.getLocalTime());
1662        buffer.append("]");
1663        buffer.append(" UNBIND conn=");
1664        buffer.append(connectionID);
1665        buffer.append(" op=");
1666        buffer.append(unbindOperation.getOperationID());
1667        buffer.append(" msgID=");
1668        buffer.append(unbindOperation.getMessageID());
1669        if (unbindOperation.isSynchronizationOperation())
1670          buffer.append(" type=synchronization");
1671    
1672    
1673        writer.writeRecord(buffer.toString());
1674      }
1675    
1676      /**
1677       * {@inheritDoc}
1678       */
1679      public DN getDN()
1680      {
1681        if(currentConfig != null)
1682        {
1683          return currentConfig.dn();
1684        }
1685        else
1686        {
1687          return null;
1688        }
1689      }
1690    }
1691