Alles begann damit (nein, dass wird keine SharePoint Märchenstunde ;)), dass einem Kunden auffiel, dass die SharePoint Beliebtheitstrends auf seinem System immer leer sind. Man muss ja auch zugeben, dass dieses Feature sehr hilfreich ist und einen Mehrwert bietet. Im Hintergrund funktioniert dies über die Usage Analytics (bzw. der gelungenen deutschen Übersetzung „Verwendungsdatensammlung“). Mittlerweile habe ich dieses Problem auch schon ein paar Mal gesehen und kann sagen, dass es meistens drei Ursachen hierfür gibt:
- Falsche/Fehlende Berechtigung auf der Usage Datenbank
- In den zu protokollierenden Ereignissen sind Seitenanforderungen und/oder Analyseverwendung nicht aktiviert
- Fehlende Event-Receiver für die Auswertung des Reports
Bei diesem Kunden war nach einem kurzen Blick auf die Usage Datenbank klar, dass der Punkt Berechtigungen nicht zutrifft. Die Usage Datenbank war mit über 12 GB Daten gefüllt. Wenn die Berechtigungen nicht passen würden, dürften überhaupt keine Daten in der Usage Datenbank zu finden sein. Auch die zu protokollierenden Ereignisse waren in der Zentraladministration richtig ausgewählt:
Also sollte man sich die Event-Receiver einmal näher ansehen, die für die SharePoint Beliebtheitstrends genutzt werden.
Für diesen Report werden zwei Event-Receiver genutzt, die die Zugriffe protokollieren:
- Analyseverwendung (bzw. auf Englisch „Analytics Usage“)
- Seitenanforderungen (bzw. auf Englisch „Page Requests“)
Mit diesem PowerShell Script kann man die Event-Receiver prüfen und ggf. manuell setzten:
# SharePoint Snapin laden if((Get-PSSnapin -Name Microsoft.SharePoint.PowerShell) -eq $null) { Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue } # Analyseverwendung Definition $aud = Get-SPUsageDefinition | where {$_.Name -like "Analyse*"} # wenn kein Event-Receiver vorhanden, füge ihn wieder hinzu if($aud.Receivers.Count -eq 0) { $aud.Receivers.Add("Microsoft.Office.Server.Search.Applications, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c", "Microsoft.Office.Server.Search.Analytics.Internal.AnalyticsCustomRequestUsageReceiver") } # wenn kein Event-Receiver vorhanden, aktiviere diesen und mache Update if($aud.EnableReceivers -eq $false) { $aud.EnableReceivers = $true $aud.Update() } # Ergebnis ausgeben $aud | fl # Seitenanforderung Definition $prud = Get-SPUsageDefinition | where {$_.Name -like "Seitenanforderungen"} # wenn kein Event-Receiver vorhanden, füge ihn wieder hinzu if($prud.Receivers.Count -eq 0) { $prud.Receivers.Add("Microsoft.Office.Server.Search.Applications, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c", "Microsoft.Office.Server.Search.Analytics.Internal.ViewRequestUsageReceiver") } # wenn kein Event-Receiver vorhanden, aktiviere diesen und mache Update if($prud.EnableReceivers -eq $false) { $prud.EnableReceivers = $true $prud.Update() } # Ergebnis ausgeben $prud | fl
Je nach eingesetzter Sprache, muss beim Namen der Definition (Zeile 8 und 27) aufgepasst werden. Dieser wird lokalisiert ausgegeben.
Wenn die Event-Receiver manuell hinzugefügt wurden, muss noch der SharePoint Timer Service auf allen Servern neu gestartet werden, damit die Änderungen erfolgreich übernommen werden. Normalerweise sollten ab diesem Zeitpunkt die SharePoint Beliebtheitstrends Berichte nicht mehr leer sein. Man muss natürlich noch einen Tag (24 h) warten, bis die gesammelten Informationen vom SharePoint (in diesem Fall Timer Job) verarbeitet werden. Bei deutschen Systemen stehen die Informationen normalerweise nach spätestens zwei Tagen zur Verfügung. Anscheinend gibt es hier einen Unterschied bzgl. den Zeitzonen, die eine entsprechend längere Wartezeit erfordern.
Allerdings wurde auch nach dieser Änderung keine SharePoint Beliebtheitstrends angezeigt, diese waren weiterhin alle leer. Also habe ich im nächsten Schritt den Timer Job manuell gestartet, der die Verarbeitung der Verwendungsdaten durchführt:
Nachdem der Timer Job erfolgreich ausgeführt wurde, habe ich einen Blick in das ULS Log geworfen und bin über folgende Meldung gestolpert:
No new usage data to process for any site between <Date> and <Date>.
SharePoint ist also immer noch der Meinung, dass keine Verwendungsdaten vorliegen. An diesem Punkt begibt man sich dann auf die Suche, wo die Verwendungsdaten denn verschwinden. Die fehlenden Event-Receiver haben wir ja bereits entsprechend korrigiert. Der erste Ansatzpunkt ist die Kontrolle, ob überhaupt Verwendungsdaten bzgl. Seitenanforderungen generiert werden. Wo die Verwendungsdaten liegen, kann man einfach über die Zentraladministration herausfinden. Dort wo auch die zu protokollierende Ereignisse ausgewählt werden, ist auch der Pfad zu den Verwendungsdaten hinterlegt. Dort gibt es einen Unterordner mit dem Namen RequestUsage
. Wenn man den Ordnerinhalt für einen kurzen Zeitraum beachtet, sollte eine .USAGE Datei erscheinen, die alle paar Minuten wieder gelöscht wird. Dann ist bei der Datensammlung alles in Ordnung. Dies kann zum Beispiel so aussehen:
Bis zu diesem Zeitpunkt haben wir sichergestellt, dass entsprechende Verwendungsdaten gesammelt werden. Weiterhin haben wir die Event-Receiver überprüft. Diese überführen die Verwendungsdaten in die Analytics (darauf basieren auch die SharePoint Beliebtheitstrends). Auf die genaue technische Realisierung gehe ich hier nicht ein, nur soviel sei verraten, dass hier ein Webservice im Spiel ist. Dieser empfängt die Verwendungsdaten und speichert diese in der Analytics-Komponente der SharePoint Suche, genauer gesagt im EventStore
. Der standardmäßige Pfad zum EventStore
liegt unter C:\Program Files\Microsoft Office Servers\14.0\Data\Office Server\Analytics_<GUID>\EventStore
. Ein funktionierender EventStore
sollte in etwa so aussehen:
Dies scheint augenscheinlich auch zu funktionieren. Aber warum ist SharePoint immer noch der Meinung, dass keine Verwendungsdaten vorliegen? An diesem Punkt hilft eigentlich nur einmal in den SharePoint Quellcode zu schauen, um herauszufinden wann genau die oben genannte Fehlermeldung geworfen wird. Zum Glück wird dieser Fehler nur an einer Stelle geworfen, nämlich hier:
Die Fehlermeldung tritt also nur auf, wenn die Funktion GetWebsWithUsageData()
keine Daten zurückliefert. Diese Funktion ist folgendermaßen definiert:
Da hatten wir aber Glück. die Funktion führt „nur“ eine SQL Abfrage aus. Diese kann man zudem mit dem SQL Management Studio recht gut debuggen. Also prüfen wir nun, ob die Abfrage wirklich kein Ergebnis zurückliefert:
declare @stime datetime declare @etime datetime set @stime = getdate() - 2 set @etime = getdate() - 1 create table #LSpartitions (partitionid tinyint) insert into #LSpartitions (partitionid) select partitionid from dbo.fn_partitionidrangemonthly(@stime, @etime) select DISTINCT SiteId, WebId, SiteUrl, WebUrl, ServerUrl from requestusage as t inner join #LSpartitions as p on t.partitionid = p.partitionid where [logtime] between @stime and @etime drop table #LSpartitions
Die Abfrage nutzt nur eine andere temporäre Tabelle, ansonsten ist der Aufruf identisch zu SharePoint. Wenn man diese Abfrage im SQL Management Studio ausführt, wird tatsächlich kein Ergebnis geliefert. Also nehmen wir uns jetzt die einzelnen Bestandteile der SQL Abfrage vor. Die separate Ausführung vom SELECT
Statement liefert auch Ergebnisse:
select partitionid from dbo.fn_partitionidrangemonthly(@stime, @etime) select DISTINCT SiteId, WebId, SiteUrl, WebUrl, ServerUrl from requestusage as t
Sobald der JOIN
durchgeführt wird, ist die Ergebnismenge wieder leer. Also muss irgendwo hier der ursächliche Fehler liegen. Der JOIN
wird auf den PartitionID
s durchgeführt. Grund genug also, um sich diese einmal näher anzusehen. Um die Datenmenge pro Tabelle nicht zu groß werden zu lassen, wird für jeden Tag im Monat und zu protokollierenden Ereignis eine eigene Tabelle genutzt. Die View requestusage
setzt die einzelnen Tage (=Tabellen) wieder zusammen.
Exemplarisch sehen die Tabellen für die App-Statistiken so aus:
Das Mapping der PartitionID
zum aktuellen Tag führt in der SQL Abfrage die Funktion dbo.fn_partitionidrangemonthly(@stime, @etime)
durch. Wenn man die Funktion mit den gleichen Datumswerten füttert, sollte auf jedem System die gleiche PartitionID
zurückgeliefert werden. Ein kurzer Vergleich auf einem System, auf dem die SharePoint Beliebtheitstrends funktionieren, hat allerdings zu einem anderen Ergebnis geführt. Bevor man jetzt schreiend vom Computer aufspringt, sollte man sich noch die Deklaration der Funktion genauer ansehen:
USE [SP-DEV01_UsageAndHealth] GO /****** Object: UserDefinedFunction [dbo].[fn_PartitionIdRangeMonthly] Script Date: 01.06.2015 15:33:11 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER FUNCTION [dbo].[fn_PartitionIdRangeMonthly] ( @BeginTime datetime, @EndTime datetime ) RETURNS @Partitions TABLE (PartitionId tinyint) AS BEGIN DECLARE @PartitionIdBegin tinyint, @PartitionIdEnd tinyint SELECT @PartitionIdBegin = dbo.fn_GetPartitionId(@BeginTime), @PartitionIdEnd = dbo.fn_GetPartitionId(@EndTime) IF (@BeginTime > @EndTime) BEGIN RETURN; END IF DATEDIFF(dd, @BeginTime, @EndTime) <= 31 BEGIN IF (@PartitionIdBegin > @PartitionIdEnd) BEGIN -- this is the exclusive rather than inclusive range INSERT INTO @Partitions SELECT PartitionId FROM dbo.MonthlyPartitions WHERE (PartitionId NOT BETWEEN @PartitionIdEnd+1 AND @PartitionIdBegin-1) END ELSE BEGIN -- include all values between the two INSERT INTO @Partitions SELECT PartitionId FROM dbo.MonthlyPartitions WHERE PartitionId BETWEEN @PartitionIdBegin AND @PartitionIdEnd END END ELSE BEGIN -- include all values INSERT INTO @Partitions SELECT PartitionId FROM dbo.MonthlyPartitions END RETURN END
In dieser Funktion passiert nicht sehr viel spannendes, was dazu beitragen könnte, dass sich das Ergebnis auf unterschiedlichen System anders verhält. Also gehen wir noch einen Schritt weiter und sehen uns die Funktion dbo.fn_GetPartitionId
an, die hier verwendet wird:
USE [SP-DEV01_UsageAndHealth] GO /****** Object: UserDefinedFunction [dbo].[fn_GetPartitionId] Script Date: 01.06.2015 15:32:36 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER FUNCTION [dbo].[fn_GetPartitionId] ( @LogTime datetime ) RETURNS tinyint AS BEGIN DECLARE @Ret tinyint SELECT @Ret = DATEDIFF(dd, '11/1/2007 00:00', @LogTime) % (31 + 1) RETURN @Ret END
Jetzt wird es schon interessanter. Hier wird die Funktion DATEDIFF
mit einem fest definierten Datum als String aufgerufen. Je nach Sprache/Land kann das Datum 11/1/2007 anders interpretiert werden: Entweder ist dies der 1. November 2007 oder der 11. Januar 2007. Und tatsächlich ist der Unterschied zwischen dem System wo die SharePoint Beliebtheitstrends funktionieren und dort wo nicht, die Installationssprache vom SQL Server. Der Kunde mit den leeren SharePoint Beliebtheitstrends hat einen deutschen SQL Server installiert. Also habe ich als letzten Versuch das Datumsformat der Funktion angepasst und den Aufruf von DATEDIFF
angepasst:
SELECT @Ret = DATEDIFF(dd, '2007-11-01 00:00', @LogTime) % (31 + 1)
Und tatsächlich, plötzlich ist SharePoint nicht mehr der Meinung, dass keine Verwendungsdaten vorliegen und auch die SharePoint Beliebtheitstrends sind nicht mehr leer.
Das Debugging an der Stelle war wirklich nicht gerade trivial und es hat sich wieder mal bewahrheitet, dass man Microsoft Produkte nur in Englisch installieren soll. Wobei das Problem mit dem Datumsformat im SharePoint auch noch an anderen Stellen auftritt. Hier könnte Microsoft auch einen etwas universelleren Ansatz nutzen, der auch andere Datumsformate akzeptiert.
Somit möchte ich am Ende noch einmal an euch appellieren, wirklich SharePoint und SQL Server in Englisch zu installieren! Das erspart ganz viele Fehler und somit auch Aufwand für die Fehlersuche.
In diesem Sinne, Happy SharePointing…
[…] Daten zugreifen können. Wie man das tun kann, habe ich bereits in einem Blogbeitrag geschrieben. Funktioniert das Sammeln und Weiterverarbeiten der Daten, sollte man sich einmal […]
Vielen Dank für diese tiefgehende, ausführliche Reise in die Tiefe der Analytics von SharePoint. Artikel mit dieser Qualität findet man im Netzt nicht viele.
Wirklich ein toller Artikel. Ich schließe mich an, selten in der Tiefe einen so guten Artikel gefunden
Ich habe in unserer SharePoint-2016-Farm dasselbe Problem. In allen WSS sind die Verwendungsberichte leer. In der Zentraladministration wird der Bericht „Anzahl der Abfragen“ jedoch mit Werten ausgegeben. Wie ist das denn zu erklären? Und was gibt es für eine Lösung für dieses Problem? Neuinstallation in Englisch ist für mich allein vom Aufwand her keine Option.
Hast Du denn schon alle beschriebenen Schritte durchgeführt? Dann ist die Sprache erstmal dafür nicht relevant.