andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 4 months ago
Clone

Blame SOURCES/0016-Issue-51165-add-new-access-log-keywords-for-wtime-an.patch

a26cad
From 282edde7950ceb2515d74fdbcc0a188131769d74 Mon Sep 17 00:00:00 2001
a26cad
From: Mark Reynolds <mreynolds@redhat.com>
a26cad
Date: Tue, 23 Jun 2020 16:38:55 -0400
a26cad
Subject: [PATCH] Issue 51165 - add new access log keywords for wtime and
a26cad
 optime
a26cad
a26cad
Description:  In addition to the "etime" stat in the access we can also
a26cad
              add the time the operation spent in the work queue, and
a26cad
              how long the actual operation took.  We now have "wtime"
a26cad
              and "optime" to track these stats in the access log.
a26cad
a26cad
              Also updated logconf for notes=F (related to a different
a26cad
              ticket), and stats for wtime and optime.
a26cad
a26cad
relates: https://pagure.io/389-ds-base/issue/51165
a26cad
a26cad
Reviewed by: ?
a26cad
---
a26cad
 ldap/admin/src/logconv.pl         | 187 +++++++++++++++++++++++++++---
a26cad
 ldap/servers/slapd/add.c          |   3 +
a26cad
 ldap/servers/slapd/bind.c         |   4 +
a26cad
 ldap/servers/slapd/delete.c       |   3 +
a26cad
 ldap/servers/slapd/modify.c       |   3 +
a26cad
 ldap/servers/slapd/modrdn.c       |   3 +
a26cad
 ldap/servers/slapd/operation.c    |  24 ++++
a26cad
 ldap/servers/slapd/opshared.c     |   3 +
a26cad
 ldap/servers/slapd/result.c       |  49 ++++----
a26cad
 ldap/servers/slapd/slap.h         |  13 ++-
a26cad
 ldap/servers/slapd/slapi-plugin.h |  26 ++++-
a26cad
 11 files changed, 269 insertions(+), 49 deletions(-)
a26cad
a26cad
diff --git a/ldap/admin/src/logconv.pl b/ldap/admin/src/logconv.pl
a26cad
index f4808a101..1ed44a888 100755
a26cad
--- a/ldap/admin/src/logconv.pl
a26cad
+++ b/ldap/admin/src/logconv.pl
a26cad
@@ -3,7 +3,7 @@
a26cad
 #
a26cad
 # BEGIN COPYRIGHT BLOCK
a26cad
 # Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
a26cad
-# Copyright (C) 2013 Red Hat, Inc.
a26cad
+# Copyright (C) 2020 Red Hat, Inc.
a26cad
 # All rights reserved.
a26cad
 #
a26cad
 # License: GPL (version 3 or any later version).
a26cad
@@ -55,7 +55,7 @@ my $reportStats = "";
a26cad
 my $dataLocation = "/tmp";
a26cad
 my $startTLSoid = "1.3.6.1.4.1.1466.20037";
a26cad
 my @statnames=qw(last last_str results srch add mod modrdn moddn cmp del abandon
a26cad
-                 conns sslconns bind anonbind unbind notesA notesU etime);
a26cad
+                 conns sslconns bind anonbind unbind notesA notesU notesF etime);
a26cad
 my $s_stats;
a26cad
 my $m_stats;
a26cad
 my $verb = "no";
a26cad
@@ -211,6 +211,7 @@ my $sslClientBindCount = 0;
a26cad
 my $sslClientFailedCount = 0;
a26cad
 my $objectclassTopCount= 0;
a26cad
 my $pagedSearchCount = 0;
a26cad
+my $invalidFilterCount = 0;
a26cad
 my $bindCount = 0;
a26cad
 my $filterCount = 0;
a26cad
 my $baseCount = 0;
a26cad
@@ -258,7 +259,7 @@ map {$conn{$_} = $_} @conncodes;
a26cad
 # hash db-backed hashes
a26cad
 my @hashnames = qw(attr rc src rsrc excount conn_hash ip_hash conncount nentries
a26cad
                    filter base ds6xbadpwd saslmech saslconnop bindlist etime oid
a26cad
-                   start_time_of_connection end_time_of_connection
a26cad
+                   start_time_of_connection end_time_of_connection notesf_conn_op
a26cad
                    notesa_conn_op notesu_conn_op etime_conn_op nentries_conn_op
a26cad
                    optype_conn_op time_conn_op srch_conn_op del_conn_op mod_conn_op
a26cad
                    mdn_conn_op cmp_conn_op bind_conn_op unbind_conn_op ext_conn_op
a26cad
@@ -926,7 +927,7 @@ if ($verb eq "yes" || $usage =~ /u/ || $usage =~ /U/){
a26cad
 			}
a26cad
 			while($op > 0){
a26cad
 				# The bind op is not the same as the search op that triggered the notes=A.
a26cad
-				# We have adjust the key by decrementing the op count until we find the last bind op.
a26cad
+				# We have to adjust the key by decrementing the op count until we find the last bind op.
a26cad
 				$op--;
a26cad
 				$binddn_key = "$srvRstCnt,$conn,$op";
a26cad
 				if (exists($bind_conn_op->{$binddn_key}) && defined($bind_conn_op->{$binddn_key})) {
a26cad
@@ -1049,9 +1050,60 @@ if ($verb eq "yes" || $usage =~ /u/ || $usage =~ /U/){
a26cad
 			}
a26cad
 		}
a26cad
 	}
a26cad
-} # end of unindexed search report
a26cad
+    print "\n";
a26cad
+}
a26cad
+
a26cad
+print "Invalid Attribute Filters:    $invalidFilterCount\n";
a26cad
+if ($invalidFilterCount > 0 && $verb eq "yes"){
a26cad
+    my $conn_hash = $hashes->{conn_hash};
a26cad
+    my $notesf_conn_op = $hashes->{notesf_conn_op};
a26cad
+    my $time_conn_op = $hashes->{time_conn_op};
a26cad
+    my $etime_conn_op = $hashes->{etime_conn_op};
a26cad
+    my $nentries_conn_op = $hashes->{nentries_conn_op};
a26cad
+    my $filter_conn_op = $hashes->{filter_conn_op};
a26cad
+    my $bind_conn_op = $hashes->{bind_conn_op};
a26cad
+    my $notesCount = 1;
a26cad
+    my $unindexedIp;
a26cad
+    my $binddn_key;
a26cad
+    my %uniqFilt = (); # hash of unique filters
a26cad
+    my %uniqFilter = (); # hash of unique filters bind dn
a26cad
+    my %uniqBindDNs = (); # hash of unique bind dn's
a26cad
+    my %uniqBindFilters = (); # hash of filters for a bind DN
a26cad
+
a26cad
+    while (my ($srcnt_conn_op, $count) = each %{$notesf_conn_op}) {
a26cad
+        my ($srvRstCnt, $conn, $op) = split(",", $srcnt_conn_op);
a26cad
+        my $attrIp = getIPfromConn($conn, $srvRstCnt);
a26cad
+        print "\n  Invalid Attribute Filter #".$notesCount." (notes=F)\n";
a26cad
+        print "  -  Date/Time:             $time_conn_op->{$srcnt_conn_op}\n";
a26cad
+        print "  -  Connection Number:     $conn\n";
a26cad
+        print "  -  Operation Number:      $op\n";
a26cad
+        print "  -  Etime:                 $etime_conn_op->{$srcnt_conn_op}\n";
a26cad
+        print "  -  Nentries:              $nentries_conn_op->{$srcnt_conn_op}\n";
a26cad
+        print "  -  IP Address:            $attrIp\n";
a26cad
+        if (exists($filter_conn_op->{$srcnt_conn_op}) && defined($filter_conn_op->{$srcnt_conn_op})) {
a26cad
+            print "  -  Search Filter:         $filter_conn_op->{$srcnt_conn_op}\n";
a26cad
+            $uniqFilt{$filter_conn_op->{$srcnt_conn_op}}++;
a26cad
+        }
a26cad
+        while($op > 0){
a26cad
+            # The bind op is not the same as the search op that triggered the notes=A.
a26cad
+            # We have to adjust the key by decrementing the op count until we find the last bind op.
a26cad
+            $op--;
a26cad
+            $binddn_key = "$srvRstCnt,$conn,$op";
a26cad
+            if (exists($bind_conn_op->{$binddn_key}) && defined($bind_conn_op->{$binddn_key})) {
a26cad
+                print "  -  Bind DN:               $bind_conn_op->{$binddn_key}\n";
a26cad
+                $uniqBindDNs{$bind_conn_op->{$binddn_key}}++;
a26cad
+                if( $uniqFilt{$filter_conn_op->{$srcnt_conn_op}} && defined($filter_conn_op->{$srcnt_conn_op})) {
a26cad
+                    $uniqBindFilters{$bind_conn_op->{$binddn_key}}{$filter_conn_op->{$srcnt_conn_op}}++;
a26cad
+                    $uniqFilter{$filter_conn_op->{$srcnt_conn_op}}{$bind_conn_op->{$binddn_key}}++;
a26cad
+                }
a26cad
+                last;
a26cad
+            }
a26cad
+        }
a26cad
+        $notesCount++;
a26cad
+    }
a26cad
+    print "\n";
a26cad
+}
a26cad
 
a26cad
-print "\n";
a26cad
 print "FDs Taken:                    $fdTaken\n";
a26cad
 print "FDs Returned:                 $fdReturned\n";
a26cad
 print "Highest FD Taken:             $highestFdTaken\n\n";
a26cad
@@ -1386,20 +1438,20 @@ if ($usage =~ /l/ || $verb eq "yes"){
a26cad
 	}
a26cad
 }
a26cad
 
a26cad
-#########################################
a26cad
-#                                       #
a26cad
-# Gather and Process the unique etimes  #
a26cad
-#                                       #
a26cad
-#########################################
a26cad
+##############################################################
a26cad
+#                                                            #
a26cad
+# Gather and Process the unique etimes, wtimes, and optimes  #
a26cad
+#                                                            #
a26cad
+##############################################################
a26cad
 
a26cad
 my $first;
a26cad
 if ($usage =~ /t/i || $verb eq "yes"){
a26cad
+	# Print the elapsed times (etime)
a26cad
+
a26cad
 	my $etime = $hashes->{etime};
a26cad
 	my @ekeys = keys %{$etime};
a26cad
-	#
a26cad
 	# print most often etimes
a26cad
-	#
a26cad
-	print "\n\n----- Top $sizeCount Most Frequent etimes -----\n\n";
a26cad
+	print "\n\n----- Top $sizeCount Most Frequent etimes (elapsed times) -----\n\n";
a26cad
 	my $eloop = 0;
a26cad
 	my $retime = 0;
a26cad
 	foreach my $et (sort { $etime->{$b} <=> $etime->{$a} } @ekeys) {
a26cad
@@ -1411,16 +1463,84 @@ if ($usage =~ /t/i || $verb eq "yes"){
a26cad
 		printf "%-8s        %-12s\n", $etime->{ $et }, "etime=$et";
a26cad
 		$eloop++;
a26cad
 	}
a26cad
-	#
a26cad
+	if ($eloop == 0) {
a26cad
+		print "None";
a26cad
+	}
a26cad
 	# print longest etimes
a26cad
-	#
a26cad
-	print "\n\n----- Top $sizeCount Longest etimes -----\n\n";
a26cad
+	print "\n\n----- Top $sizeCount Longest etimes (elapsed times) -----\n\n";
a26cad
 	$eloop = 0;
a26cad
 	foreach my $et (sort { $b <=> $a } @ekeys) {
a26cad
 		if ($eloop == $sizeCount) { last; }
a26cad
 		printf "%-12s    %-10s\n","etime=$et",$etime->{ $et };
a26cad
 		$eloop++;
a26cad
 	}
a26cad
+	if ($eloop == 0) {
a26cad
+		print "None";
a26cad
+	}
a26cad
+
a26cad
+	# Print the wait times (wtime)
a26cad
+
a26cad
+	my $wtime = $hashes->{wtime};
a26cad
+	my @wkeys = keys %{$wtime};
a26cad
+	# print most often wtimes
a26cad
+	print "\n\n----- Top $sizeCount Most Frequent wtimes (wait times) -----\n\n";
a26cad
+	$eloop = 0;
a26cad
+	$retime = 0;
a26cad
+	foreach my $et (sort { $wtime->{$b} <=> $wtime->{$a} } @wkeys) {
a26cad
+		if ($eloop == $sizeCount) { last; }
a26cad
+		if ($retime ne "2"){
a26cad
+			$first = $et;
a26cad
+			$retime = "2";
a26cad
+		}
a26cad
+		printf "%-8s        %-12s\n", $wtime->{ $et }, "wtime=$et";
a26cad
+		$eloop++;
a26cad
+	}
a26cad
+	if ($eloop == 0) {
a26cad
+		print "None";
a26cad
+	}
a26cad
+	# print longest wtimes
a26cad
+	print "\n\n----- Top $sizeCount Longest wtimes (wait times) -----\n\n";
a26cad
+	$eloop = 0;
a26cad
+	foreach my $et (sort { $b <=> $a } @wkeys) {
a26cad
+		if ($eloop == $sizeCount) { last; }
a26cad
+		printf "%-12s    %-10s\n","wtime=$et",$wtime->{ $et };
a26cad
+		$eloop++;
a26cad
+	}
a26cad
+	if ($eloop == 0) {
a26cad
+		print "None";
a26cad
+	}
a26cad
+
a26cad
+	# Print the operation times (optime)
a26cad
+
a26cad
+	my $optime = $hashes->{optime};
a26cad
+	my @opkeys = keys %{$optime};
a26cad
+	# print most often optimes
a26cad
+	print "\n\n----- Top $sizeCount Most Frequent optimes (actual operation times) -----\n\n";
a26cad
+	$eloop = 0;
a26cad
+	$retime = 0;
a26cad
+	foreach my $et (sort { $optime->{$b} <=> $optime->{$a} } @opkeys) {
a26cad
+		if ($eloop == $sizeCount) { last; }
a26cad
+		if ($retime ne "2"){
a26cad
+			$first = $et;
a26cad
+			$retime = "2";
a26cad
+		}
a26cad
+		printf "%-8s        %-12s\n", $optime->{ $et }, "optime=$et";
a26cad
+		$eloop++;
a26cad
+	}
a26cad
+	if ($eloop == 0) {
a26cad
+		print "None";
a26cad
+	}
a26cad
+	# print longest optimes
a26cad
+	print "\n\n----- Top $sizeCount Longest optimes (actual operation times) -----\n\n";
a26cad
+	$eloop = 0;
a26cad
+	foreach my $et (sort { $b <=> $a } @opkeys) {
a26cad
+		if ($eloop == $sizeCount) { last; }
a26cad
+		printf "%-12s    %-10s\n","optime=$et",$optime->{ $et };
a26cad
+		$eloop++;
a26cad
+	}
a26cad
+	if ($eloop == 0) {
a26cad
+		print "None";
a26cad
+	}
a26cad
 }
a26cad
 
a26cad
 #######################################
a26cad
@@ -2152,6 +2272,26 @@ sub parseLineNormal
a26cad
 	if (m/ RESULT err=/ && m/ notes=[A-Z,]*P/){
a26cad
 		$pagedSearchCount++;
a26cad
 	}
a26cad
+	if (m/ RESULT err=/ && m/ notes=[A-Z,]*F/){
a26cad
+		$invalidFilterCount++;
a26cad
+		$con = "";
a26cad
+		if ($_ =~ /conn= *([0-9A-Z]+)/i){
a26cad
+			$con = $1;
a26cad
+			if ($_ =~ /op= *([0-9\-]+)/i){ $op = $1;}
a26cad
+		}
a26cad
+
a26cad
+		if($reportStats){ inc_stats('notesF',$s_stats,$m_stats); }
a26cad
+        if ($usage =~ /u/ || $usage =~ /U/ || $verb eq "yes"){
a26cad
+            if($_ =~ /etime= *([0-9.]+)/i ){
a26cad
+                if($1 >= $minEtime){
a26cad
+                    $hashes->{etime_conn_op}->{"$serverRestartCount,$con,$op"} = $1;
a26cad
+                    $hashes->{notesf_conn_op}->{"$serverRestartCount,$con,$op"}++;
a26cad
+                    if ($_ =~ / *([0-9a-z:\/]+)/i){ $hashes->{time_conn_op}->{"$serverRestartCount,$con,$op"} = $1; }
a26cad
+                    if ($_ =~ /nentries= *([0-9]+)/i ){ $hashes->{nentries_conn_op}->{"$serverRestartCount,$con,$op"} = $1; }
a26cad
+                }
a26cad
+            }
a26cad
+        }
a26cad
+	}
a26cad
 	if (m/ notes=[A-Z,]*A/){
a26cad
 		$con = "";
a26cad
 		if ($_ =~ /conn= *([0-9A-Z]+)/i){
a26cad
@@ -2435,6 +2575,16 @@ sub parseLineNormal
a26cad
 		if ($usage =~ /t/i || $verb eq "yes"){ $hashes->{etime}->{$etime_val}++; }
a26cad
 		if ($reportStats){ inc_stats_val('etime',$etime_val,$s_stats,$m_stats); }
a26cad
 	}
a26cad
+	if ($_ =~ /wtime= *([0-9.]+)/ ) {
a26cad
+		my $wtime_val = $1;
a26cad
+		if ($usage =~ /t/i || $verb eq "yes"){ $hashes->{wtime}->{$wtime_val}++; }
a26cad
+		if ($reportStats){ inc_stats_val('wtime',$wtime_val,$s_stats,$m_stats); }
a26cad
+	}
a26cad
+	if ($_ =~ /optime= *([0-9.]+)/ ) {
a26cad
+		my $optime_val = $1;
a26cad
+		if ($usage =~ /t/i || $verb eq "yes"){ $hashes->{optime}->{$optime_val}++; }
a26cad
+		if ($reportStats){ inc_stats_val('optime',$optime_val,$s_stats,$m_stats); }
a26cad
+	}
a26cad
 	if ($_ =~ / tag=101 / || $_ =~ / tag=111 / || $_ =~ / tag=100 / || $_ =~ / tag=115 /){
a26cad
 		if ($_ =~ / nentries= *([0-9]+)/i ){ 
a26cad
 			my $nents = $1;
a26cad
@@ -2555,7 +2705,7 @@ sub parseLineNormal
a26cad
 			}
a26cad
 		}
a26cad
 	}
a26cad
-	if (/ RESULT err=/ && / tag=97 nentries=0 etime=/ && $_ =~ /dn=\"(.*)\"/i){
a26cad
+	if (/ RESULT err=/ && / tag=97 nentries=0 / && $_ =~ /dn=\"(.*)\"/i){
a26cad
 		# Check if this is a sasl bind, if see we need to add the RESULT's dn as a bind dn
a26cad
 		my $binddn = $1;
a26cad
 		my ($conn, $op);
a26cad
@@ -2680,6 +2830,7 @@ print_stats_block
a26cad
 						 $stats->{'unbind'},
a26cad
 						 $stats->{'notesA'},
a26cad
 						 $stats->{'notesU'},
a26cad
+						 $stats->{'notesF'},
a26cad
 						 $stats->{'etime'}),
a26cad
 					"\n" );
a26cad
 			} else {
a26cad
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
a26cad
index 06ca1ee79..52c64fa3c 100644
a26cad
--- a/ldap/servers/slapd/add.c
a26cad
+++ b/ldap/servers/slapd/add.c
a26cad
@@ -441,6 +441,9 @@ op_shared_add(Slapi_PBlock *pb)
a26cad
     internal_op = operation_is_flag_set(operation, OP_FLAG_INTERNAL);
a26cad
     pwpolicy = new_passwdPolicy(pb, slapi_entry_get_dn(e));
a26cad
 
a26cad
+    /* Set the time we actually started the operation */
a26cad
+    slapi_operation_set_time_started(operation);
a26cad
+
a26cad
     /* target spec is used to decide which plugins are applicable for the operation */
a26cad
     operation_set_target_spec(operation, slapi_entry_get_sdn(e));
a26cad
 
a26cad
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
a26cad
index 310216e89..55f865077 100644
a26cad
--- a/ldap/servers/slapd/bind.c
a26cad
+++ b/ldap/servers/slapd/bind.c
a26cad
@@ -87,6 +87,10 @@ do_bind(Slapi_PBlock *pb)
a26cad
         send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
a26cad
         goto free_and_return;
a26cad
     }
a26cad
+
a26cad
+    /* Set the time we actually started the operation */
a26cad
+    slapi_operation_set_time_started(pb_op);
a26cad
+
a26cad
     ber = pb_op->o_ber;
a26cad
 
a26cad
     /*
a26cad
diff --git a/ldap/servers/slapd/delete.c b/ldap/servers/slapd/delete.c
a26cad
index c0e61adf1..1a7209317 100644
a26cad
--- a/ldap/servers/slapd/delete.c
a26cad
+++ b/ldap/servers/slapd/delete.c
a26cad
@@ -236,6 +236,9 @@ op_shared_delete(Slapi_PBlock *pb)
a26cad
     slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
a26cad
     internal_op = operation_is_flag_set(operation, OP_FLAG_INTERNAL);
a26cad
 
a26cad
+    /* Set the time we actually started the operation */
a26cad
+    slapi_operation_set_time_started(operation);
a26cad
+
a26cad
     sdn = slapi_sdn_new_dn_byval(rawdn);
a26cad
     dn = slapi_sdn_get_dn(sdn);
a26cad
     slapi_pblock_set(pb, SLAPI_DELETE_TARGET_SDN, (void *)sdn);
a26cad
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
a26cad
index 259bedfff..a186dbde3 100644
a26cad
--- a/ldap/servers/slapd/modify.c
a26cad
+++ b/ldap/servers/slapd/modify.c
a26cad
@@ -626,6 +626,9 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
a26cad
     slapi_pblock_get(pb, SLAPI_SKIP_MODIFIED_ATTRS, &skip_modified_attrs);
a26cad
     slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
a26cad
 
a26cad
+    /* Set the time we actually started the operation */
a26cad
+    slapi_operation_set_time_started(operation);
a26cad
+
a26cad
     if (sdn) {
a26cad
         passin_sdn = 1;
a26cad
     } else {
a26cad
diff --git a/ldap/servers/slapd/modrdn.c b/ldap/servers/slapd/modrdn.c
a26cad
index 3efe584a7..e04916b83 100644
a26cad
--- a/ldap/servers/slapd/modrdn.c
a26cad
+++ b/ldap/servers/slapd/modrdn.c
a26cad
@@ -417,6 +417,9 @@ op_shared_rename(Slapi_PBlock *pb, int passin_args)
a26cad
     internal_op = operation_is_flag_set(operation, OP_FLAG_INTERNAL);
a26cad
     slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
a26cad
 
a26cad
+    /* Set the time we actually started the operation */
a26cad
+    slapi_operation_set_time_started(operation);
a26cad
+
a26cad
     /*
a26cad
      * If ownership has not been passed to this function, we replace the
a26cad
      * string input fields within the pblock with strdup'd copies.  Why?
a26cad
diff --git a/ldap/servers/slapd/operation.c b/ldap/servers/slapd/operation.c
a26cad
index ff16cd906..4dd3481c7 100644
a26cad
--- a/ldap/servers/slapd/operation.c
a26cad
+++ b/ldap/servers/slapd/operation.c
a26cad
@@ -651,3 +651,27 @@ slapi_operation_time_expiry(Slapi_Operation *o, time_t timeout, struct timespec
a26cad
 {
a26cad
     slapi_timespec_expire_rel(timeout, &(o->o_hr_time_rel), expiry);
a26cad
 }
a26cad
+
a26cad
+/* Set the time the operation actually started */
a26cad
+void
a26cad
+slapi_operation_set_time_started(Slapi_Operation *o)
a26cad
+{
a26cad
+	clock_gettime(CLOCK_MONOTONIC, &(o->o_hr_time_started_rel));
a26cad
+}
a26cad
+
a26cad
+/* The time diff of how long the operation took once it actually started */
a26cad
+void
a26cad
+slapi_operation_op_time_elapsed(Slapi_Operation *o, struct timespec *elapsed)
a26cad
+{
a26cad
+    struct timespec o_hr_time_now;
a26cad
+    clock_gettime(CLOCK_MONOTONIC, &o_hr_time_now);
a26cad
+
a26cad
+    slapi_timespec_diff(&o_hr_time_now, &(o->o_hr_time_started_rel), elapsed);
a26cad
+}
a26cad
+
a26cad
+/* The time diff the operation waited in the work queue */
a26cad
+void
a26cad
+slapi_operation_workq_time_elapsed(Slapi_Operation *o, struct timespec *elapsed)
a26cad
+{
a26cad
+    slapi_timespec_diff(&(o->o_hr_time_started_rel), &(o->o_hr_time_rel), elapsed);
a26cad
+}
a26cad
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
a26cad
index 9fe78655c..c0bc5dcd0 100644
a26cad
--- a/ldap/servers/slapd/opshared.c
a26cad
+++ b/ldap/servers/slapd/opshared.c
a26cad
@@ -284,6 +284,9 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
a26cad
     slapi_pblock_get(pb, SLAPI_SEARCH_TARGET_SDN, &sdn;;
a26cad
     slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
a26cad
 
a26cad
+    /* Set the time we actually started the operation */
a26cad
+    slapi_operation_set_time_started(operation);
a26cad
+
a26cad
     if (NULL == sdn) {
a26cad
         sdn = slapi_sdn_new_dn_byval(base);
a26cad
         slapi_pblock_set(pb, SLAPI_SEARCH_TARGET_SDN, sdn);
a26cad
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
a26cad
index 0b13c30e9..61efb6f8d 100644
a26cad
--- a/ldap/servers/slapd/result.c
a26cad
+++ b/ldap/servers/slapd/result.c
a26cad
@@ -1975,6 +1975,8 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
     CSN *operationcsn = NULL;
a26cad
     char csn_str[CSN_STRSIZE + 5];
a26cad
     char etime[ETIME_BUFSIZ] = {0};
a26cad
+    char wtime[ETIME_BUFSIZ] = {0};
a26cad
+    char optime[ETIME_BUFSIZ] = {0};
a26cad
     int pr_idx = -1;
a26cad
     int pr_cookie = -1;
a26cad
     uint32_t operation_notes;
a26cad
@@ -1982,19 +1984,26 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
     int32_t op_id;
a26cad
     int32_t op_internal_id;
a26cad
     int32_t op_nested_count;
a26cad
+    struct timespec o_hr_time_end;
a26cad
 
a26cad
     get_internal_conn_op(&connid, &op_id, &op_internal_id, &op_nested_count);
a26cad
-
a26cad
     slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx);
a26cad
     slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_COOKIE, &pr_cookie);
a26cad
-
a26cad
     internal_op = operation_is_flag_set(op, OP_FLAG_INTERNAL);
a26cad
 
a26cad
-    struct timespec o_hr_time_end;
a26cad
+    /* total elapsed time */
a26cad
     slapi_operation_time_elapsed(op, &o_hr_time_end);
a26cad
+    snprintf(etime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec);
a26cad
+
a26cad
+    /* wait time */
a26cad
+    slapi_operation_workq_time_elapsed(op, &o_hr_time_end);
a26cad
+    snprintf(wtime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec);
a26cad
+
a26cad
+    /* op time */
a26cad
+    slapi_operation_op_time_elapsed(op, &o_hr_time_end);
a26cad
+    snprintf(optime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec);
a26cad
 
a26cad
 
a26cad
-    snprintf(etime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec);
a26cad
 
a26cad
     operation_notes = slapi_pblock_get_operation_notes(pb);
a26cad
 
a26cad
@@ -2025,16 +2034,16 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
         if (!internal_op) {
a26cad
             slapi_log_access(LDAP_DEBUG_STATS,
a26cad
                              "conn=%" PRIu64 " op=%d RESULT err=%d"
a26cad
-                             " tag=%" BERTAG_T " nentries=%d etime=%s%s%s"
a26cad
+                             " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s"
a26cad
                              ", SASL bind in progress\n",
a26cad
                              op->o_connid,
a26cad
                              op->o_opid,
a26cad
                              err, tag, nentries,
a26cad
-                             etime,
a26cad
+                             wtime, optime, etime,
a26cad
                              notes_str, csn_str);
a26cad
         } else {
a26cad
 
a26cad
-#define LOG_SASLMSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s, SASL bind in progress\n"
a26cad
+#define LOG_SASLMSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s, SASL bind in progress\n"
a26cad
             slapi_log_access(LDAP_DEBUG_ARGS,
a26cad
                              connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_SASLMSG_FMT :
a26cad
                                            LOG_CONN_OP_FMT_EXT_INT LOG_SASLMSG_FMT,
a26cad
@@ -2043,7 +2052,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
                              op_internal_id,
a26cad
                              op_nested_count,
a26cad
                              err, tag, nentries,
a26cad
-                             etime,
a26cad
+                             wtime, optime, etime,
a26cad
                              notes_str, csn_str);
a26cad
         }
a26cad
     } else if (op->o_tag == LDAP_REQ_BIND && err == LDAP_SUCCESS) {
a26cad
@@ -2057,15 +2066,15 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
         if (!internal_op) {
a26cad
             slapi_log_access(LDAP_DEBUG_STATS,
a26cad
                              "conn=%" PRIu64 " op=%d RESULT err=%d"
a26cad
-                             " tag=%" BERTAG_T " nentries=%d etime=%s%s%s"
a26cad
+                             " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s"
a26cad
                              " dn=\"%s\"\n",
a26cad
                              op->o_connid,
a26cad
                              op->o_opid,
a26cad
                              err, tag, nentries,
a26cad
-                             etime,
a26cad
+                             wtime, optime, etime,
a26cad
                              notes_str, csn_str, dn ? dn : "");
a26cad
         } else {
a26cad
-#define LOG_BINDMSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s dn=\"%s\"\n"
a26cad
+#define LOG_BINDMSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s dn=\"%s\"\n"
a26cad
             slapi_log_access(LDAP_DEBUG_ARGS,
a26cad
                              connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_BINDMSG_FMT :
a26cad
                                            LOG_CONN_OP_FMT_EXT_INT LOG_BINDMSG_FMT,
a26cad
@@ -2074,7 +2083,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
                              op_internal_id,
a26cad
                              op_nested_count,
a26cad
                              err, tag, nentries,
a26cad
-                             etime,
a26cad
+                             wtime, optime, etime,
a26cad
                              notes_str, csn_str, dn ? dn : "");
a26cad
         }
a26cad
         slapi_ch_free((void **)&dn;;
a26cad
@@ -2083,15 +2092,15 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
             if (!internal_op) {
a26cad
                 slapi_log_access(LDAP_DEBUG_STATS,
a26cad
                                  "conn=%" PRIu64 " op=%d RESULT err=%d"
a26cad
-                                 " tag=%" BERTAG_T " nentries=%d etime=%s%s%s"
a26cad
+                                 " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s"
a26cad
                                  " pr_idx=%d pr_cookie=%d\n",
a26cad
                                  op->o_connid,
a26cad
                                  op->o_opid,
a26cad
                                  err, tag, nentries,
a26cad
-                                 etime,
a26cad
+                                 wtime, optime, etime,
a26cad
                                  notes_str, csn_str, pr_idx, pr_cookie);
a26cad
             } else {
a26cad
-#define LOG_PRMSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s pr_idx=%d pr_cookie=%d \n"
a26cad
+#define LOG_PRMSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s pr_idx=%d pr_cookie=%d \n"
a26cad
                 slapi_log_access(LDAP_DEBUG_ARGS,
a26cad
                                  connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_PRMSG_FMT :
a26cad
                                                LOG_CONN_OP_FMT_EXT_INT LOG_PRMSG_FMT,
a26cad
@@ -2100,7 +2109,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
                                  op_internal_id,
a26cad
                                  op_nested_count,
a26cad
                                  err, tag, nentries,
a26cad
-                                 etime,
a26cad
+                                 wtime, optime, etime,
a26cad
                                  notes_str, csn_str, pr_idx, pr_cookie);
a26cad
             }
a26cad
         } else if (!internal_op) {
a26cad
@@ -2114,11 +2123,11 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
             }
a26cad
             slapi_log_access(LDAP_DEBUG_STATS,
a26cad
                              "conn=%" PRIu64 " op=%d RESULT err=%d"
a26cad
-                             " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n",
a26cad
+                             " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s%s\n",
a26cad
                              op->o_connid,
a26cad
                              op->o_opid,
a26cad
                              err, tag, nentries,
a26cad
-                             etime,
a26cad
+                             wtime, optime, etime,
a26cad
                              notes_str, csn_str, ext_str);
a26cad
             if (pbtxt) {
a26cad
                 /* if !pbtxt ==> ext_str == "".  Don't free ext_str. */
a26cad
@@ -2126,7 +2135,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
             }
a26cad
         } else {
a26cad
             int optype;
a26cad
-#define LOG_MSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n"
a26cad
+#define LOG_MSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s\n"
a26cad
             slapi_log_access(LDAP_DEBUG_ARGS,
a26cad
                              connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_MSG_FMT :
a26cad
                                            LOG_CONN_OP_FMT_EXT_INT LOG_MSG_FMT,
a26cad
@@ -2135,7 +2144,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries
a26cad
                              op_internal_id,
a26cad
                              op_nested_count,
a26cad
                              err, tag, nentries,
a26cad
-                             etime,
a26cad
+                             wtime, optime, etime,
a26cad
                              notes_str, csn_str);
a26cad
             /*
a26cad
              *  If this is an unindexed search we should log it in the error log if
a26cad
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
a26cad
index cef8c789c..8e76393c3 100644
a26cad
--- a/ldap/servers/slapd/slap.h
a26cad
+++ b/ldap/servers/slapd/slap.h
a26cad
@@ -1538,16 +1538,17 @@ typedef struct slapi_operation_results
a26cad
  */
a26cad
 typedef struct op
a26cad
 {
a26cad
-    BerElement *o_ber;             /* ber of the request          */
a26cad
-    ber_int_t o_msgid;             /* msgid of the request          */
a26cad
-    ber_tag_t o_tag;               /* tag of the request          */
a26cad
+    BerElement *o_ber;             /* ber of the request */
a26cad
+    ber_int_t o_msgid;             /* msgid of the request */
a26cad
+    ber_tag_t o_tag;               /* tag of the request */
a26cad
     struct timespec o_hr_time_rel; /* internal system time op initiated */
a26cad
     struct timespec o_hr_time_utc; /* utc system time op initiated */
a26cad
-    int o_isroot;                  /* requestor is manager          */
a26cad
+    struct timespec o_hr_time_started_rel; /* internal system time op started */
a26cad
+    int o_isroot;                  /* requestor is manager */
a26cad
     Slapi_DN o_sdn;                /* dn bound when op was initiated */
a26cad
-    char *o_authtype;              /* auth method used to bind dn      */
a26cad
+    char *o_authtype;              /* auth method used to bind dn */
a26cad
     int o_ssf;                     /* ssf for this operation (highest between SASL and TLS/SSL) */
a26cad
-    int o_opid;                    /* id of this operation          */
a26cad
+    int o_opid;                    /* id of this operation */
a26cad
     PRUint64 o_connid;             /* id of conn initiating this op; for logging only */
a26cad
     void *o_handler_data;
a26cad
     result_handler o_result_handler;
a26cad
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
a26cad
index 834a98742..8d9c3fa6a 100644
a26cad
--- a/ldap/servers/slapd/slapi-plugin.h
a26cad
+++ b/ldap/servers/slapd/slapi-plugin.h
a26cad
@@ -8210,13 +8210,29 @@ void slapi_operation_time_elapsed(Slapi_Operation *o, struct timespec *elapsed);
a26cad
  */
a26cad
 void slapi_operation_time_initiated(Slapi_Operation *o, struct timespec *initiated);
a26cad
 /**
a26cad
- * Given an operation and a timeout, return a populate struct with the expiry
a26cad
- * time of the operation suitable for checking with slapi_timespec_expire_check
a26cad
+ * Given an operation, determine the time elapsed since the op
a26cad
+ * was actually started.
a26cad
  *
a26cad
- * \param Slapi_Operation o - the operation that is in progress
a26cad
- * \param time_t timeout the seconds relative to operation initiation to expiry at.
a26cad
- * \param struct timespec *expiry the timespec to popluate with the relative expiry.
a26cad
+ * \param Slapi_Operation o - the operation which is inprogress
a26cad
+ * \param struct timespec *elapsed - location where the time difference will be
a26cad
+ * placed.
a26cad
+ */
a26cad
+void slapi_operation_op_time_elapsed(Slapi_Operation *o, struct timespec *elapsed);
a26cad
+/**
a26cad
+ * Given an operation, determine the time elapsed that the op spent
a26cad
+ * in the work queue before actually being dispatched to a worker thread
a26cad
+ *
a26cad
+ * \param Slapi_Operation o - the operation which is inprogress
a26cad
+ * \param struct timespec *elapsed - location where the time difference will be
a26cad
+ * placed.
a26cad
+ */
a26cad
+void slapi_operation_workq_time_elapsed(Slapi_Operation *o, struct timespec *elapsed);
a26cad
+/**
a26cad
+ * Set the time the operation actually started
a26cad
+ *
a26cad
+ * \param Slapi_Operation o - the operation which is inprogress
a26cad
  */
a26cad
+void slapi_operation_set_time_started(Slapi_Operation *o);
a26cad
 #endif
a26cad
 
a26cad
 /**
a26cad
-- 
a26cad
2.26.2
a26cad