SharePoint Beliebtheitstrends sind leer

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:

  1. Falsche/Fehlende Berechtigung auf der Usage Datenbank
  2. In den zu protokollierenden Ereignissen sind Seitenanforderungen und/oder Analyseverwendung nicht aktiviert
  3. 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:

SharePoint Beliebtheitstrends

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:

  1. Analyseverwendung (bzw. auf Englisch „Analytics Usage“)
  2. 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:

SharePoint Beliebtheitstrends

 

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:

SharePoint Beliebtheitstrends

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:

SharePoint Beliebtheitstrends

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:

SharePoint Beliebtheitstrends

Die Fehlermeldung tritt also nur auf, wenn die Funktion GetWebsWithUsageData() keine Daten zurückliefert. Diese Funktion ist folgendermaßen definiert:

SharePoint Beliebtheitstrends

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 PartitionIDs 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:

SharePoint Beliebtheitstrends

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…

5 Kommentare

  1. 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.

  2. 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.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert