andykimpe / rpms / 389-ds-base

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

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

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